diff --git a/doc/changelog.dox b/doc/changelog.dox index a3e1597ec4..2834686af4 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -335,6 +335,9 @@ See also: @ref CompressedImageView::size() as well as @ref Trade::ImageData::size() now return a @cpp const& @ce instead of a value to allow creating a @relativeref{Corrade,Containers::StridedArrayView} slice onto this member. +- @ref Image, @ref CompressedImage, @ref ImageView, @ref CompressedImageView + as well as @ref Trade::ImageData are now able to annotate array, cube map + and cube map array images using @ref ImageFlags @subsubsection changelog-latest-changes-debugtools DebugTools library @@ -916,6 +919,11 @@ See also: changed to have input first and output second, for consistency with other interfaces, together with a switch to @ref Containers::StringView. The original signature is marked as deprecated. +- Due to introduction of @ref ImageFlags, @ref Trade::ImageData constructors + that were taking @cpp const void* importerState @ce as the last parameter + are now deprecated in favor of constructors that take @ref ImageFlags *and* + `importerState`. Code that wasn't passing the `importerState` parameter + isn't affected by this change. - @cpp Trade::TextureData::Type @ce was deprecated in favor of @ref Trade::TextureType that is much less annoying to type, in addition @cpp Trade::TextureData::Type::Cube @ce was deprecated in favor of diff --git a/src/Magnum/CMakeLists.txt b/src/Magnum/CMakeLists.txt index b12aa39498..6dc531e071 100644 --- a/src/Magnum/CMakeLists.txt +++ b/src/Magnum/CMakeLists.txt @@ -74,6 +74,7 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.h.cmake # Files shared between main library and unit test library set(Magnum_SRCS FileCallback.cpp + ImageFlags.cpp PixelStorage.cpp Resource.cpp Sampler.cpp @@ -95,6 +96,7 @@ set(Magnum_HEADERS DimensionTraits.h FileCallback.h Image.h + ImageFlags.h ImageView.h Magnum.h Mesh.h diff --git a/src/Magnum/Image.cpp b/src/Magnum/Image.cpp index 23d2a64768..2c93748617 100644 --- a/src/Magnum/Image.cpp +++ b/src/Magnum/Image.cpp @@ -31,12 +31,15 @@ namespace Magnum { -template Image::Image(const PixelStorage storage, const PixelFormat format, const VectorTypeFor& size, Containers::Array&& data) noexcept: Image{storage, format, {}, pixelFormatSize(format), size, std::move(data)} {} +template Image::Image(const PixelStorage storage, const PixelFormat format, const VectorTypeFor& size, Containers::Array&& data, const ImageFlags flags) noexcept: Image{storage, format, {}, pixelFormatSize(format), size, std::move(data), flags} {} -template Image::Image(const PixelStorage storage, const UnsignedInt format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size, Containers::Array&& data) noexcept: Image{storage, pixelFormatWrap(format), formatExtra, pixelSize, size, std::move(data)} {} +template Image::Image(const PixelStorage storage, const UnsignedInt format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size, Containers::Array&& data, const ImageFlags flags) noexcept: Image{storage, pixelFormatWrap(format), formatExtra, pixelSize, size, std::move(data), flags} {} -template Image::Image(const PixelStorage storage, const PixelFormat format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size, Containers::Array&& data) noexcept: _storage{storage}, _format{format}, _formatExtra{formatExtra}, _pixelSize{pixelSize}, _size{size}, _data{std::move(data)} { +template Image::Image(const PixelStorage storage, const PixelFormat format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size, Containers::Array&& data, const ImageFlags flags) noexcept: _storage{storage}, _format{format}, _formatExtra{formatExtra}, _pixelSize{pixelSize}, _flags{flags}, _size{size}, _data{std::move(data)} { CORRADE_ASSERT(Implementation::imageDataSize(*this) <= _data.size(), "Image: data too small, got" << _data.size() << "but expected at least" << Implementation::imageDataSize(*this) << "bytes", ); + #ifndef CORRADE_NO_ASSERT + Implementation::checkImageFlagsForSize("Image:", flags, size); + #endif } template Image::Image(const PixelStorage storage, const PixelFormat format) noexcept: Image{storage, format, {}, pixelFormatSize(format)} {} @@ -45,7 +48,7 @@ template Image::Image(const PixelStorage sto template Image::Image(const PixelStorage storage, const PixelFormat format, const UnsignedInt formatExtra, const UnsignedInt pixelSize) noexcept: _storage{storage}, _format{format}, _formatExtra{formatExtra}, _pixelSize{pixelSize}, _data{} {} -template Image::Image(Image&& other) noexcept: _storage{std::move(other._storage)}, _format{std::move(other._format)}, _formatExtra{std::move(other._formatExtra)}, _pixelSize{std::move(other._pixelSize)}, _size{std::move(other._size)}, _data{std::move(other._data)} { +template Image::Image(Image&& other) noexcept: _storage{std::move(other._storage)}, _format{std::move(other._format)}, _formatExtra{std::move(other._formatExtra)}, _pixelSize{std::move(other._pixelSize)}, _flags{std::move(other._flags)}, _size{std::move(other._size)}, _data{std::move(other._data)} { other._size = {}; } @@ -55,17 +58,18 @@ template Image& Image::operator= swap(_format, other._format); swap(_formatExtra, other._formatExtra); swap(_pixelSize, other._pixelSize); + swap(_flags, other._flags); swap(_size, other._size); swap(_data, other._data); return *this; } template Image::operator BasicMutableImageView() { - return BasicMutableImageView{_storage, _format, _formatExtra, _pixelSize, _size, _data}; + return BasicMutableImageView{_storage, _format, _formatExtra, _pixelSize, _size, _data, _flags}; } template Image::operator BasicImageView() const { - return BasicImageView{_storage, _format, _formatExtra, _pixelSize, _size, _data}; + return BasicImageView{_storage, _format, _formatExtra, _pixelSize, _size, _data, _flags}; } template std::pair, VectorTypeFor> Image::dataProperties() const { @@ -86,13 +90,17 @@ template Containers::Array Image::rele return data; } -template CompressedImage::CompressedImage(const CompressedPixelStorage storage, const CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data) noexcept: _storage{storage}, _format{format}, _size{size}, _data{std::move(data)} {} +template CompressedImage::CompressedImage(const CompressedPixelStorage storage, const CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data, const ImageFlags flags) noexcept: _storage{storage}, _format{format}, _flags{flags}, _size{size}, _data{std::move(data)} { + #ifndef CORRADE_NO_ASSERT + Implementation::checkImageFlagsForSize("CompressedImage:", flags, size); + #endif +} -template CompressedImage::CompressedImage(const CompressedPixelStorage storage, const UnsignedInt format, const VectorTypeFor& size, Containers::Array&& data) noexcept: CompressedImage{storage, compressedPixelFormatWrap(format), size, std::move(data)} {} +template CompressedImage::CompressedImage(const CompressedPixelStorage storage, const UnsignedInt format, const VectorTypeFor& size, Containers::Array&& data, const ImageFlags flags) noexcept: CompressedImage{storage, compressedPixelFormatWrap(format), size, std::move(data), flags} {} template CompressedImage::CompressedImage(const CompressedPixelStorage storage) noexcept: _storage{storage}, _format{} {} -template CompressedImage::CompressedImage(CompressedImage&& other) noexcept: _storage{std::move(other._storage)}, _format{std::move(other._format)}, _size{std::move(other._size)}, _data{std::move(other._data)} +template CompressedImage::CompressedImage(CompressedImage&& other) noexcept: _storage{std::move(other._storage)}, _format{std::move(other._format)}, _flags{other._flags}, _size{std::move(other._size)}, _data{std::move(other._data)} { other._size = {}; } @@ -101,17 +109,18 @@ template CompressedImage& CompressedImage CompressedImage::operator BasicMutableCompressedImageView() { - return BasicMutableCompressedImageView{_storage, _format, _size, _data}; + return BasicMutableCompressedImageView{_storage, _format, _size, _data, _flags}; } template CompressedImage::operator BasicCompressedImageView() const { - return BasicCompressedImageView{_storage, _format, _size, _data}; + return BasicCompressedImageView{_storage, _format, _size, _data, _flags}; } template std::pair, VectorTypeFor> CompressedImage::dataProperties() const { diff --git a/src/Magnum/Image.h b/src/Magnum/Image.h index 10a3323429..d4074456ef 100644 --- a/src/Magnum/Image.h +++ b/src/Magnum/Image.h @@ -32,6 +32,7 @@ #include #include "Magnum/DimensionTraits.h" +#include "Magnum/ImageFlags.h" #include "Magnum/PixelStorage.h" #ifndef DOXYGEN_GENERATING_OUTPUT @@ -126,30 +127,35 @@ template class Image { * @param format Format of pixel data * @param size Image size * @param data Image data + * @param flags Image layout flags * * The @p data array is expected to be of proper size for given - * parameters. + * parameters. For a 3D image, if @p flags contain + * @ref ImageFlag3D::CubeMap, the @p size is expected to match its + * restrictions. */ - explicit Image(PixelStorage storage, PixelFormat format, const VectorTypeFor& size, Containers::Array&& data) noexcept; + explicit Image(PixelStorage storage, PixelFormat format, const VectorTypeFor& size, Containers::Array&& data, ImageFlags flags = {}) noexcept; /** * @brief Constructor * @param format Format of pixel data * @param size Image size * @param data Image data + * @param flags Image layout flags * - * Equivalent to calling @ref Image(PixelStorage, PixelFormat, const VectorTypeFor&, Containers::Array&&) + * Equivalent to calling @ref Image(PixelStorage, PixelFormat, const VectorTypeFor&, Containers::Array&&, ImageFlags) * with default-constructed @ref PixelStorage. */ - explicit Image(PixelFormat format, const VectorTypeFor& size, Containers::Array&& data) noexcept: Image{{}, format, size, std::move(data)} {} + explicit Image(PixelFormat format, const VectorTypeFor& size, Containers::Array&& data, ImageFlags flags = {}) noexcept: Image{{}, format, size, std::move(data), flags} {} /** * @brief Construct an image placeholder * @param storage Storage of pixel data * @param format Format of pixel data * - * Size is set to zero and data pointer to @cpp nullptr @ce. Move over - * a non-empty instance to make it useful. + * Size is set to zero, data pointer to @cpp nullptr @ce and data + * layout flags are empty. Move over a non-empty instance to make it + * useful. */ /*implicit*/ Image(PixelStorage storage, PixelFormat format) noexcept; @@ -170,8 +176,9 @@ template class Image { * @param pixelSize Size of a pixel in given format, in bytes * @param size Image size, in pixels * @param data Image data + * @param flags Image layout flags * - * Unlike with @ref Image(PixelStorage, PixelFormat, const VectorTypeFor&, Containers::Array&&), + * Unlike with @ref Image(PixelStorage, PixelFormat, const VectorTypeFor&, Containers::Array&&, ImageFlags), * where pixel size is calculated automatically using * @ref pixelFormatSize(), this allows you to specify an * implementation-specific pixel format and pixel size directly. Uses @@ -179,16 +186,18 @@ template class Image { * @ref PixelFormat. * * The @p data array is expected to be of proper size for given - * parameters. + * parameters. For a 3D image, if @p flags contain + * @ref ImageFlag3D::CubeMap, the @p size is expected to match its + * restrictions. */ - explicit Image(PixelStorage storage, UnsignedInt format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, Containers::Array&& data) noexcept; + explicit Image(PixelStorage storage, UnsignedInt format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, Containers::Array&& data, ImageFlags flags = {}) noexcept; /** @overload * * Equivalent to the above for @p format already wrapped with * @ref pixelFormatWrap(). */ - explicit Image(PixelStorage storage, PixelFormat format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, Containers::Array&& data) noexcept; + explicit Image(PixelStorage storage, PixelFormat format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, Containers::Array&& data, ImageFlags flags = {}) noexcept; /** * @brief Construct an image placeholder with implementation-specific pixel format @@ -219,12 +228,13 @@ template class Image { * @param formatExtra Additional pixel format specifier * @param size Image size * @param data Image data + * @param flags Image layout flags * * Uses ADL to find a corresponding @cpp pixelFormatSize(T, U) @ce - * overload, then calls @ref Image(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, Containers::Array&&) + * overload, then calls @ref Image(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, Containers::Array&&, ImageFlags) * with calculated pixel size. */ - template explicit Image(PixelStorage storage, T format, U formatExtra, const VectorTypeFor& size, Containers::Array&& data) noexcept; + template explicit Image(PixelStorage storage, T format, U formatExtra, const VectorTypeFor& size, Containers::Array&& data, ImageFlags flags = {}) noexcept; /** * @brief Construct an image with implementation-specific pixel format @@ -232,12 +242,13 @@ template class Image { * @param format Format of pixel data * @param size Image size * @param data Image data + * @param flags Image layout flags * * Uses ADL to find a corresponding @cpp pixelFormatSize(T) @ce - * overload, then calls @ref Image(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, Containers::Array&&) + * overload, then calls @ref Image(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, Containers::Array&&, ImageFlags) * with calculated pixel size and @p formatExtra set to @cpp 0 @ce. */ - template explicit Image(PixelStorage storage, T format, const VectorTypeFor& size, Containers::Array&& data) noexcept; + template explicit Image(PixelStorage storage, T format, const VectorTypeFor& size, Containers::Array&& data, ImageFlags flags = {}) noexcept; /** * @brief Construct an image with implementation-specific pixel format @@ -245,22 +256,24 @@ template class Image { * @param formatExtra Additional pixel format specifier * @param size Image size * @param data Image data + * @param flags Image layout flags * - * Equivalent to calling @ref Image(PixelStorage, T, U, const VectorTypeFor&, Containers::Array&&) + * Equivalent to calling @ref Image(PixelStorage, T, U, const VectorTypeFor&, Containers::Array&&, ImageFlags) * with default-constructed @ref PixelStorage. */ - template explicit Image(T format, U formatExtra, const VectorTypeFor& size, Containers::Array&& data) noexcept: Image{{}, format, formatExtra, size, std::move(data)} {} + template explicit Image(T format, U formatExtra, const VectorTypeFor& size, Containers::Array&& data, ImageFlags flags = {}) noexcept: Image{{}, format, formatExtra, size, std::move(data), flags} {} /** * @brief Construct an image with implementation-specific pixel format * @param format Format of pixel data * @param size Image size * @param data Image data + * @param flags Image layout flags * - * Equivalent to calling @ref Image(PixelStorage, T, const VectorTypeFor&, Containers::Array&&) + * Equivalent to calling @ref Image(PixelStorage, T, const VectorTypeFor&, Containers::Array&&, ImageFlags) * with default-constructed @ref PixelStorage. */ - template explicit Image(T format, const VectorTypeFor& size, Containers::Array&& data) noexcept: Image{{}, format, size, std::move(data)} {} + template explicit Image(T format, const VectorTypeFor& size, Containers::Array&& data, ImageFlags flags = {}) noexcept: Image{{}, format, size, std::move(data), flags} {} /** * @brief Construct an image placeholder with implementation-specific pixel format @@ -332,6 +345,12 @@ template class Image { another function in an oneliner (e.g. saving screenshot) */ /*implicit*/ operator BasicMutableImageView(); + /** + * @brief Layout flags + * @m_since_latest + */ + ImageFlags flags() const { return _flags; } + /** @brief Storage of pixel data */ PixelStorage storage() const { return _storage; } @@ -469,7 +488,11 @@ template class Image { PixelStorage _storage; PixelFormat _format; UnsignedInt _formatExtra; + /** @todo this could be a short, saving 8 bytes for 1D and 3D images on + 64bit and 4 bytes for all dimensions on 32bit. Worth the pain? */ UnsignedInt _pixelSize; + /* 2-byte gap */ + ImageFlags _flags; VectorTypeFor _size; Containers::Array _data; }; @@ -528,19 +551,24 @@ template class CompressedImage { * @param format Format of compressed pixel data * @param size Image size * @param data Image data + * @param flags Image layout flags + * + * For a 3D image, if @p flags contain @ref ImageFlag3D::CubeMap, the + * @p size is expected to match its restrictions. */ - explicit CompressedImage(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data) noexcept; + explicit CompressedImage(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data, ImageFlags flags = {}) noexcept; /** * @brief Constructor * @param format Format of compressed pixel data * @param size Image size * @param data Image data + * @param flags Image layout flags * - * Equivalent to calling @ref CompressedImage(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, Containers::Array&&) + * Equivalent to calling @ref CompressedImage(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, Containers::Array&&, ImageFlags) * with default-constructed @ref CompressedPixelStorage. */ - explicit CompressedImage(CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data) noexcept: CompressedImage{{}, format, size, std::move(data)} {} + explicit CompressedImage(CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data, ImageFlags flags = {}) noexcept: CompressedImage{{}, format, size, std::move(data), flags} {} /** * @brief Construct a compressed image with implementation-specific format @@ -548,29 +576,35 @@ template class CompressedImage { * @param format Format of compressed pixel data * @param size Image size * @param data Image data + * @param flags Image layout flags * * Uses @ref compressedPixelFormatWrap() internally to convert * @p format to @ref CompressedPixelFormat. + * + * For a 3D image, if @p flags contain @ref ImageFlag3D::CubeMap, the + * @p size is expected to match its restrictions. */ - template explicit CompressedImage(CompressedPixelStorage storage, T format, const VectorTypeFor& size, Containers::Array&& data) noexcept; + template explicit CompressedImage(CompressedPixelStorage storage, T format, const VectorTypeFor& size, Containers::Array&& data, ImageFlags flags = {}) noexcept; /** * @brief Construct a compressed image with implementation-specific format * @param format Format of compressed pixel data * @param size Image size * @param data Image data + * @param flags Image layout flags * - * Equivalent to calling @ref CompressedImage(CompressedPixelStorage, T, const VectorTypeFor&, Containers::Array&&) + * Equivalent to calling @ref CompressedImage(CompressedPixelStorage, T, const VectorTypeFor&, Containers::Array&&, ImageFlags) * with default-constructed @ref CompressedPixelStorage. */ - template explicit CompressedImage(T format, const VectorTypeFor& size, Containers::Array&& data) noexcept: CompressedImage{{}, format, size, std::move(data)} {} + template explicit CompressedImage(T format, const VectorTypeFor& size, Containers::Array&& data, ImageFlags flags = {}) noexcept: CompressedImage{{}, format, size, std::move(data), flags} {} /** * @brief Construct an image placeholder * @param storage Storage of compressed pixel data * - * Format is undefined, size is zero and data is @cpp nullptr @ce. Move - * over a non-empty instance to make it useful. + * Format is undefined, size is zero, data is @cpp nullptr @ce and + * data layout flags are empty. Move over a non-empty instance to make + * it useful. */ /*implicit*/ CompressedImage(CompressedPixelStorage storage) noexcept; @@ -605,6 +639,12 @@ template class CompressedImage { another function in an oneliner (e.g. saving screenshot) */ /*implicit*/ operator BasicMutableCompressedImageView(); + /** + * @brief Layout flags + * @m_since_latest + */ + ImageFlags flags() const { return _flags; } + /** @brief Storage of compressed pixel data */ CompressedPixelStorage storage() const { return _storage; } @@ -691,10 +731,11 @@ template class CompressedImage { private: /* To be made public once block size and block data size are stored together with the image */ - explicit CompressedImage(CompressedPixelStorage storage, UnsignedInt format, const VectorTypeFor& size, Containers::Array&& data) noexcept; + explicit CompressedImage(CompressedPixelStorage storage, UnsignedInt format, const VectorTypeFor& size, Containers::Array&& data, ImageFlags flags) noexcept; CompressedPixelStorage _storage; CompressedPixelFormat _format; + ImageFlags _flags; VectorTypeFor _size; Containers::Array _data; }; @@ -708,12 +749,12 @@ typedef CompressedImage<2> CompressedImage2D; /** @brief Three-dimensional compressed image */ typedef CompressedImage<3> CompressedImage3D; -template template inline Image::Image(const PixelStorage storage, const T format, const U formatExtra, const VectorTypeFor& size, Containers::Array&& data) noexcept: Image{storage, UnsignedInt(format), UnsignedInt(formatExtra), Implementation::pixelFormatSizeAdl(format, formatExtra), size, std::move(data)} { +template template inline Image::Image(const PixelStorage storage, const T format, const U formatExtra, const VectorTypeFor& size, Containers::Array&& data, const ImageFlags flags) noexcept: Image{storage, UnsignedInt(format), UnsignedInt(formatExtra), Implementation::pixelFormatSizeAdl(format, formatExtra), size, std::move(data), flags} { static_assert(sizeof(T) <= 4 && sizeof(U) <= 4, "format types larger than 32bits are not supported"); } -template template inline Image::Image(const PixelStorage storage, const T format, const VectorTypeFor& size, Containers::Array&& data) noexcept: Image{storage, UnsignedInt(format), {}, Implementation::pixelFormatSizeAdl(format), size, std::move(data)} { +template template inline Image::Image(const PixelStorage storage, const T format, const VectorTypeFor& size, Containers::Array&& data, const ImageFlags flags) noexcept: Image{storage, UnsignedInt(format), {}, Implementation::pixelFormatSizeAdl(format), size, std::move(data), flags} { static_assert(sizeof(T) <= 4, "format types larger than 32bits are not supported"); } @@ -728,7 +769,7 @@ template template inline Image::Ima "format types larger than 32bits are not supported"); } -template template inline CompressedImage::CompressedImage(const CompressedPixelStorage storage, const T format, const VectorTypeFor& size, Containers::Array&& data) noexcept: CompressedImage{storage, UnsignedInt(format), size, std::move(data)} { +template template inline CompressedImage::CompressedImage(const CompressedPixelStorage storage, const T format, const VectorTypeFor& size, Containers::Array&& data, const ImageFlags flags) noexcept: CompressedImage{storage, UnsignedInt(format), size, std::move(data), flags} { static_assert(sizeof(T) <= 4, "format types larger than 32bits are not supported"); } diff --git a/src/Magnum/ImageFlags.cpp b/src/Magnum/ImageFlags.cpp new file mode 100644 index 0000000000..a7e8a6c643 --- /dev/null +++ b/src/Magnum/ImageFlags.cpp @@ -0,0 +1,101 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021, 2022 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "ImageFlags.h" + +#include + +namespace Magnum { + +Debug& operator<<(Debug& debug, const ImageFlag1D value) { + const bool packed = debug.immediateFlags() >= Debug::Flag::Packed; + + if(!packed) + debug << "ImageFlag1D" << Debug::nospace; + + switch(value) { + /* LCOV_EXCL_START */ + #define _c(value) case ImageFlag1D::value: return debug << (packed ? "" : "::") << Debug::nospace << #value; + #undef _c + /* LCOV_EXCL_STOP */ + } + + return debug << (packed ? "" : "(") << Debug::nospace << reinterpret_cast(UnsignedShort(value)) << Debug::nospace << (packed ? "" : ")"); +} + +Debug& operator<<(Debug& debug, const ImageFlag2D value) { + const bool packed = debug.immediateFlags() >= Debug::Flag::Packed; + + if(!packed) + debug << "ImageFlag2D" << Debug::nospace; + + switch(value) { + /* LCOV_EXCL_START */ + #define _c(value) case ImageFlag2D::value: return debug << (packed ? "" : "::") << Debug::nospace << #value; + _c(Array) + #undef _c + /* LCOV_EXCL_STOP */ + } + + return debug << (packed ? "" : "(") << Debug::nospace << reinterpret_cast(UnsignedShort(value)) << Debug::nospace << (packed ? "" : ")"); +} + +Debug& operator<<(Debug& debug, const ImageFlag3D value) { + const bool packed = debug.immediateFlags() >= Debug::Flag::Packed; + + if(!packed) + debug << "ImageFlag3D" << Debug::nospace; + + switch(value) { + /* LCOV_EXCL_START */ + #define _c(value) case ImageFlag3D::value: return debug << (packed ? "" : "::") << Debug::nospace << #value; + _c(Array) + _c(CubeMap) + #undef _c + /* LCOV_EXCL_STOP */ + } + + return debug << (packed ? "" : "(") << Debug::nospace << reinterpret_cast(UnsignedShort(value)) << Debug::nospace << (packed ? "" : ")"); +} + +Debug& operator<<(Debug& debug, const ImageFlags1D value) { + return Containers::enumSetDebugOutput(debug, value, debug.immediateFlags() >= Debug::Flag::Packed ? "{}" : "ImageFlags1D{}", { + }); +} + +Debug& operator<<(Debug& debug, const ImageFlags2D value) { + return Containers::enumSetDebugOutput(debug, value, debug.immediateFlags() >= Debug::Flag::Packed ? "{}" : "ImageFlags2D{}", { + ImageFlag2D::Array + }); +} + +Debug& operator<<(Debug& debug, const ImageFlags3D value) { + return Containers::enumSetDebugOutput(debug, value, debug.immediateFlags() >= Debug::Flag::Packed ? "{}" : "ImageFlags3D{}", { + ImageFlag3D::Array, + ImageFlag3D::CubeMap + }); +} + +} diff --git a/src/Magnum/ImageFlags.h b/src/Magnum/ImageFlags.h new file mode 100644 index 0000000000..7149d0dd60 --- /dev/null +++ b/src/Magnum/ImageFlags.h @@ -0,0 +1,183 @@ +#ifndef Magnum_ImageFlags_h +#define Magnum_ImageFlags_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021, 2022 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Enum @ref Magnum::ImageFlag1D, @ref Magnum::ImageFlag2D, @ref Magnum::ImageFlag3D, enum set @ref Magnum::ImageFlags1D, @ref Magnum::ImageFlags2D, @ref Magnum::ImageFlags3D, alias @ref Magnum::ImageFlag, @ref Magnum::ImageFlags + * @m_since_latest + */ + +#include + +#include "Magnum/Magnum.h" +#include "Magnum/visibility.h" + +namespace Magnum { + +/** +@brief 1D image layout flag +@m_since_latest + +Used by @ref Image1D, @ref ImageView1D and @ref Trade::ImageData1D. Currently +no flags specific to 1D images are defined. +@see @ref ImageFlags1D +*/ +enum class ImageFlag1D: UnsignedShort {}; + +/** +@brief 2D image layout flag +@m_since_latest + +Used by @ref Image2D, @ref ImageView2D and @ref Trade::ImageData2D. +@see @ref ImageFlags2D +*/ +enum class ImageFlag2D: UnsignedShort { + /** + * The image is a 1D array instead of 2D. I.e., no filtering is done along + * the Y axis and mip levels don't shorten along the Y axis. + * + * Guaranteed to have the same value as @ref ImageFlag3D::Array. + */ + Array = 1 << 0, +}; + +/** +@brief 3D image layout flag +@m_since_latest + +Used by @ref Image3D, @ref ImageView3D and @ref Trade::ImageData3D. +@see @ref ImageFlags3D +*/ +enum class ImageFlag3D: UnsignedShort { + /** + * The image is a 2D array instead of 3D. I.e., no filtering is done along + * the Z axis and mip levels don't shorten along the Z axis. + * + * Guaranteed to have the same value as @ref ImageFlag2D::Array. + */ + Array = 1 << 0, + + /** + * The image is a cube map instead of 3D. I.e., there's exactly six square + * 2D faces in order (+X, -X, +Y, -Y, +Z, -Z), filtering is done on face + * edges, and mip levels don't shorten along the Z axis. If combined with + * @ref ImageFlag3D::Array, the image is a cube map array, consisting of an + * exact multiple of six square 2D faces, with each six layers being one + * cube map. + */ + CubeMap = 1 << 1 +}; + +/** @debugoperatorenum{ImageFlag1D} */ +MAGNUM_EXPORT Debug& operator<<(Debug& debug, ImageFlag1D value); + +/** @debugoperatorenum{ImageFlag2D} */ +MAGNUM_EXPORT Debug& operator<<(Debug& debug, ImageFlag2D value); + +/** @debugoperatorenum{ImageFlag3D} */ +MAGNUM_EXPORT Debug& operator<<(Debug& debug, ImageFlag3D value); + +/** +@brief 1D image layout flags +@m_since_latest + +Used by @ref Image1D, @ref ImageView1D, @ref Trade::ImageData1D and +@ref GL::BufferImage1D. +*/ +typedef Containers::EnumSet ImageFlags1D; + +/** +@brief 2D image layout flags +@m_since_latest + +Used by @ref Image2D, @ref ImageView2D, @ref Trade::ImageData2D and +@ref GL::BufferImage2D. +*/ +typedef Containers::EnumSet ImageFlags2D; + +/** +@brief 3D image layout flags +@m_since_latest + +Used by @ref Image3D, @ref ImageView3D, @ref Trade::ImageData3D and +@ref GL::BufferImage3D. +*/ +typedef Containers::EnumSet ImageFlags3D; + +CORRADE_ENUMSET_OPERATORS(ImageFlags1D) +CORRADE_ENUMSET_OPERATORS(ImageFlags2D) +CORRADE_ENUMSET_OPERATORS(ImageFlags3D) + +/** @debugoperatorenum{ImageFlags1D} */ +MAGNUM_EXPORT Debug& operator<<(Debug& debug, ImageFlags1D value); + +/** @debugoperatorenum{ImageFlags2D} */ +MAGNUM_EXPORT Debug& operator<<(Debug& debug, ImageFlags2D value); + +/** @debugoperatorenum{ImageFlags3D} */ +MAGNUM_EXPORT Debug& operator<<(Debug& debug, ImageFlags3D value); + +namespace Implementation { + +template struct ImageFlagTraits; +template<> struct ImageFlagTraits<1> { + typedef ImageFlag1D Type; + typedef ImageFlags1D SetType; +}; +template<> struct ImageFlagTraits<2> { + typedef ImageFlag2D Type; + typedef ImageFlags2D SetType; +}; +template<> struct ImageFlagTraits<3> { + typedef ImageFlag3D Type; + typedef ImageFlags3D SetType; +}; + +} + +/** +@brief Image layout flag +@m_since_latest + +Expands to @ref ImageFlag1D, @ref ImageFlag2D or @ref ImageFlag3D based on +dimension count. +@see @ref ImageFlags +*/ +template using ImageFlag = typename Implementation::ImageFlagTraits::Type; + +/** +@brief Image layout flags +@m_since_latest + +Expands to @ref ImageFlags1D, @ref ImageFlags2D or @ref ImageFlags3D based on +dimension count. +@see @ref ImageFlag +*/ +template using ImageFlags = typename Implementation::ImageFlagTraits::SetType; + +} + +#endif diff --git a/src/Magnum/ImageView.cpp b/src/Magnum/ImageView.cpp index 9bbb537868..e3a2c375e0 100644 --- a/src/Magnum/ImageView.cpp +++ b/src/Magnum/ImageView.cpp @@ -30,11 +30,11 @@ namespace Magnum { -template ImageView::ImageView(const PixelStorage storage, const PixelFormat format, const VectorTypeFor& size, const Containers::ArrayView data) noexcept: ImageView{storage, format, {}, pixelFormatSize(format), size, data} {} +template ImageView::ImageView(const PixelStorage storage, const PixelFormat format, const VectorTypeFor& size, const Containers::ArrayView data, const ImageFlags flags) noexcept: ImageView{storage, format, {}, pixelFormatSize(format), size, data, flags} {} -template ImageView::ImageView(const PixelStorage storage, const UnsignedInt format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size, const Containers::ArrayView data) noexcept: ImageView{storage, pixelFormatWrap(format), formatExtra, pixelSize, size, data} {} +template ImageView::ImageView(const PixelStorage storage, const UnsignedInt format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size, const Containers::ArrayView data, const ImageFlags flags) noexcept: ImageView{storage, pixelFormatWrap(format), formatExtra, pixelSize, size, data, flags} {} -template ImageView::ImageView(const PixelStorage storage, const PixelFormat format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size, const Containers::ArrayView data) noexcept: _storage{storage}, _format{format}, _formatExtra{formatExtra}, _pixelSize{pixelSize}, _size{size}, _data{reinterpret_cast(data.data()), data.size()} { +template ImageView::ImageView(const PixelStorage storage, const PixelFormat format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size, const Containers::ArrayView data, const ImageFlags flags) noexcept: _storage{storage}, _format{format}, _formatExtra{formatExtra}, _pixelSize{pixelSize}, _flags{flags}, _size{size}, _data{reinterpret_cast(data.data()), data.size()} { #ifdef MAGNUM_BUILD_DEPRECATED #ifndef CORRADE_NO_ASSERT if(size.product() && !_data && !_data.size()) @@ -44,13 +44,20 @@ template ImageView::ImageView(co #else CORRADE_ASSERT(Implementation::imageDataSize(*this) <= _data.size(), "ImageView: data too small, got" << _data.size() << "but expected at least" << Implementation::imageDataSize(*this) << "bytes", ); #endif + #ifndef CORRADE_NO_ASSERT + Implementation::checkImageFlagsForSize("ImageView:", flags, size); + #endif } -template ImageView::ImageView(const PixelStorage storage, const PixelFormat format, const VectorTypeFor& size) noexcept: ImageView{storage, format, {}, pixelFormatSize(format), size} {} +template ImageView::ImageView(const PixelStorage storage, const PixelFormat format, const VectorTypeFor& size, const ImageFlags flags) noexcept: ImageView{storage, format, {}, pixelFormatSize(format), size, flags} {} -template ImageView::ImageView(const PixelStorage storage, const UnsignedInt format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size) noexcept: ImageView{storage, pixelFormatWrap(format), formatExtra, pixelSize, size} {} +template ImageView::ImageView(const PixelStorage storage, const UnsignedInt format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size, const ImageFlags flags) noexcept: ImageView{storage, pixelFormatWrap(format), formatExtra, pixelSize, size, flags} {} -template ImageView::ImageView(const PixelStorage storage, const PixelFormat format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size) noexcept: _storage{storage}, _format{format}, _formatExtra{formatExtra}, _pixelSize{pixelSize}, _size{size}, _data{nullptr} {} +template ImageView::ImageView(const PixelStorage storage, const PixelFormat format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size, const ImageFlags flags) noexcept: _storage{storage}, _format{format}, _formatExtra{formatExtra}, _pixelSize{pixelSize}, _flags{flags}, _size{size}, _data{nullptr} { + #ifndef CORRADE_NO_ASSERT + Implementation::checkImageFlagsForSize("ImageView:", flags, size); + #endif +} template std::pair, VectorTypeFor> ImageView::dataProperties() const { return Implementation::imageDataProperties(*this); @@ -66,13 +73,21 @@ template auto ImageView::pixels( return Implementation::imagePixelView(*this, data()); } -template CompressedImageView::CompressedImageView(const CompressedPixelStorage storage, const CompressedPixelFormat format, const VectorTypeFor& size, const Containers::ArrayView data) noexcept: _storage{storage}, _format{format}, _size{size}, _data{reinterpret_cast(data.data()), data.size()} {} +template CompressedImageView::CompressedImageView(const CompressedPixelStorage storage, const CompressedPixelFormat format, const VectorTypeFor& size, const Containers::ArrayView data, const ImageFlags flags) noexcept: _storage{storage}, _format{format}, _flags{flags}, _size{size}, _data{reinterpret_cast(data.data()), data.size()} { + #ifndef CORRADE_NO_ASSERT + Implementation::checkImageFlagsForSize("CompressedImageView:", flags, size); + #endif +} -template CompressedImageView::CompressedImageView(const CompressedPixelStorage storage, const CompressedPixelFormat format, const VectorTypeFor& size) noexcept: _storage{storage}, _format{format}, _size{size} {} +template CompressedImageView::CompressedImageView(const CompressedPixelStorage storage, const CompressedPixelFormat format, const VectorTypeFor& size, const ImageFlags flags) noexcept: _storage{storage}, _format{format}, _flags{flags}, _size{size} { + #ifndef CORRADE_NO_ASSERT + Implementation::checkImageFlagsForSize("CompressedImageView:", flags, size); + #endif +} -template CompressedImageView::CompressedImageView(const CompressedPixelStorage storage, const UnsignedInt format, const VectorTypeFor& size, const Containers::ArrayView data) noexcept: CompressedImageView{storage, compressedPixelFormatWrap(format), size, data} {} +template CompressedImageView::CompressedImageView(const CompressedPixelStorage storage, const UnsignedInt format, const VectorTypeFor& size, const Containers::ArrayView data, const ImageFlags flags) noexcept: CompressedImageView{storage, compressedPixelFormatWrap(format), size, data, flags} {} -template CompressedImageView::CompressedImageView(const CompressedPixelStorage storage, const UnsignedInt format, const VectorTypeFor& size) noexcept: CompressedImageView{storage, compressedPixelFormatWrap(format), size} {} +template CompressedImageView::CompressedImageView(const CompressedPixelStorage storage, const UnsignedInt format, const VectorTypeFor& size, const ImageFlags flags) noexcept: CompressedImageView{storage, compressedPixelFormatWrap(format), size, flags} {} template std::pair, VectorTypeFor> CompressedImageView::dataProperties() const { return Implementation::compressedImageDataProperties(*this); diff --git a/src/Magnum/ImageView.h b/src/Magnum/ImageView.h index e6bd75a65b..a04d08fb76 100644 --- a/src/Magnum/ImageView.h +++ b/src/Magnum/ImageView.h @@ -32,6 +32,7 @@ #include #include "Magnum/DimensionTraits.h" +#include "Magnum/ImageFlags.h" #include "Magnum/PixelStorage.h" #include "Magnum/Math/Vector3.h" @@ -171,43 +172,51 @@ template class ImageView { * @param format Format of pixel data * @param size Image size * @param data Image data + * @param flags Image layout flags * * The @p data array is expected to be of proper size for given - * parameters. + * parameters. For a 3D image, if @p flags contain + * @ref ImageFlag3D::CubeMap, the @p size is expected to match its + * restrictions. */ - explicit ImageView(PixelStorage storage, PixelFormat format, const VectorTypeFor& size, Containers::ArrayView data) noexcept; + explicit ImageView(PixelStorage storage, PixelFormat format, const VectorTypeFor& size, Containers::ArrayView data, ImageFlags flags = {}) noexcept; /** * @brief Constructor * @param format Format of pixel data * @param size Image size * @param data Image data + * @param flags Image layout flags * - * Equivalent to calling @ref ImageView(PixelStorage, PixelFormat, const VectorTypeFor&, Containers::ArrayView) + * Equivalent to calling @ref ImageView(PixelStorage, PixelFormat, const VectorTypeFor&, Containers::ArrayView, ImageFlags) * with default-constructed @ref PixelStorage. */ - explicit ImageView(PixelFormat format, const VectorTypeFor& size, Containers::ArrayView data) noexcept: ImageView{{}, format, size, data} {} + explicit ImageView(PixelFormat format, const VectorTypeFor& size, Containers::ArrayView data, ImageFlags flags = {}) noexcept: ImageView{{}, format, size, data, flags} {} /** * @brief Construct an empty view * @param storage Storage of pixel data * @param format Format of pixel data * @param size Image size + * @param flags Image layout flags * * Data pointer is set to @cpp nullptr @ce, call @ref setData() to - * assign a memory view to the image. + * assign a memory view to the image. For a 3D image, if @p flags + * contain @ref ImageFlag3D::CubeMap, the @p size is expected to match + * its restrictions. */ - explicit ImageView(PixelStorage storage, PixelFormat format, const VectorTypeFor& size) noexcept; + explicit ImageView(PixelStorage storage, PixelFormat format, const VectorTypeFor& size, ImageFlags flags = {}) noexcept; /** * @brief Construct an empty view * @param format Format of pixel data * @param size Image size + * @param flags Image layout flags * - * Equivalent to calling @ref ImageView(PixelStorage, PixelFormat, const VectorTypeFor&) + * Equivalent to calling @ref ImageView(PixelStorage, PixelFormat, const VectorTypeFor&, ImageFlags) * with default-constructed @ref PixelStorage. */ - explicit ImageView(PixelFormat format, const VectorTypeFor& size) noexcept: ImageView{{}, format, size} {} + explicit ImageView(PixelFormat format, const VectorTypeFor& size, ImageFlags flags = {}) noexcept: ImageView{{}, format, size, flags} {} /** * @brief Construct an image view with implementation-specific pixel format @@ -217,8 +226,9 @@ template class ImageView { * @param pixelSize Size of a pixel in given format, in bytes * @param size Image size, in pixels * @param data Image data + * @param flags Image layout flags * - * Unlike with @ref ImageView(PixelStorage, PixelFormat, const VectorTypeFor&, Containers::ArrayView), + * Unlike with @ref ImageView(PixelStorage, PixelFormat, const VectorTypeFor&, Containers::ArrayView, ImageFlags), * where pixel size is calculated automatically using * @ref pixelFormatSize(), this allows you to specify an * implementation-specific pixel format and pixel size directly. Uses @@ -226,16 +236,18 @@ template class ImageView { * @ref PixelFormat. * * The @p data array is expected to be of proper size for given - * parameters. + * parameters. For a 3D image, if @p flags contain + * @ref ImageFlag3D::CubeMap, the @p size is expected to match its + * restrictions. */ - explicit ImageView(PixelStorage storage, UnsignedInt format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, Containers::ArrayView data) noexcept; + explicit ImageView(PixelStorage storage, UnsignedInt format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, Containers::ArrayView data, ImageFlags flags = {}) noexcept; /** @overload * * Equivalent to the above for @p format already wrapped with * @ref pixelFormatWrap(). */ - explicit ImageView(PixelStorage storage, PixelFormat format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, Containers::ArrayView data) noexcept; + explicit ImageView(PixelStorage storage, PixelFormat format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, Containers::ArrayView data, ImageFlags flags = {}) noexcept; /** * @brief Construct an empty view with implementation-specific pixel format @@ -244,8 +256,9 @@ template class ImageView { * @param formatExtra Additional pixel format specifier * @param pixelSize Size of a pixel in given format, in bytes * @param size Image size, in pixels + * @param flags Image layout flags * - * Unlike with @ref ImageView(PixelStorage, PixelFormat, const VectorTypeFor&), + * Unlike with @ref ImageView(PixelStorage, PixelFormat, const VectorTypeFor&, ImageFlags), * where pixel size is calculated automatically using * @ref pixelFormatSize(), this allows you to specify an * implementation-specific pixel format and pixel size directly. Uses @@ -253,16 +266,18 @@ template class ImageView { * @ref PixelFormat. * * Data pointer is set to @cpp nullptr @ce, call @ref setData() to - * assign a memory view to the image. + * assign a memory view to the image. For a 3D image, if @p flags + * contain @ref ImageFlag3D::CubeMap, the @p size is expected to match + * its restrictions. */ - explicit ImageView(PixelStorage storage, UnsignedInt format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size) noexcept; + explicit ImageView(PixelStorage storage, UnsignedInt format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, ImageFlags flags = {}) noexcept; /** @overload * * Equivalent to the above for @p format already wrapped with * @ref pixelFormatWrap(). */ - explicit ImageView(PixelStorage storage, PixelFormat format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size) noexcept; + explicit ImageView(PixelStorage storage, PixelFormat format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, ImageFlags flags = {}) noexcept; /** * @brief Construct an image view with implementation-specific pixel format @@ -271,12 +286,13 @@ template class ImageView { * @param formatExtra Additional pixel format specifier * @param size Image size * @param data Image data + * @param flags Image layout flags * * Uses ADL to find a corresponding @cpp pixelFormatSize(T, U) @ce - * overload, then calls @ref ImageView(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, Containers::ArrayView) + * overload, then calls @ref ImageView(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, Containers::ArrayView, ImageFlags) * with calculated pixel size. */ - template explicit ImageView(PixelStorage storage, U format, V formatExtra, const VectorTypeFor& size, Containers::ArrayView data) noexcept; + template explicit ImageView(PixelStorage storage, U format, V formatExtra, const VectorTypeFor& size, Containers::ArrayView data, ImageFlags flags = {}) noexcept; /** * @brief Construct an image view with implementation-specific pixel format @@ -284,12 +300,13 @@ template class ImageView { * @param format Format of pixel data * @param size Image size * @param data Image data + * @param flags Image layout flags * * Uses ADL to find a corresponding @cpp pixelFormatSize(T) @ce - * overload, then calls @ref ImageView(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, Containers::ArrayView) + * overload, then calls @ref ImageView(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, Containers::ArrayView, ImageFlags) * with calculated pixel size and @p formatExtra set to @cpp 0 @ce. */ - template explicit ImageView(PixelStorage storage, U format, const VectorTypeFor& size, Containers::ArrayView data) noexcept; + template explicit ImageView(PixelStorage storage, U format, const VectorTypeFor& size, Containers::ArrayView data, ImageFlags flags = {}) noexcept; /** * @brief Construct an image view with implementation-specific pixel format @@ -297,22 +314,24 @@ template class ImageView { * @param formatExtra Additional pixel format specifier * @param size Image size * @param data Image data + * @param flags Image layout flags * - * Equivalent to calling @ref ImageView(PixelStorage, U, V, const VectorTypeFor&, Containers::ArrayView) + * Equivalent to calling @ref ImageView(PixelStorage, U, V, const VectorTypeFor&, Containers::ArrayView, ImageFlags) * with default-constructed @ref PixelStorage. */ - template explicit ImageView(U format, V formatExtra, const VectorTypeFor& size, Containers::ArrayView data) noexcept: ImageView{{}, format, formatExtra, size, data} {} + template explicit ImageView(U format, V formatExtra, const VectorTypeFor& size, Containers::ArrayView data, ImageFlags flags = {}) noexcept: ImageView{{}, format, formatExtra, size, data, flags} {} /** * @brief Construct an image view with implementation-specific pixel format * @param format Format of pixel data * @param size Image size * @param data Image data + * @param flags Image layout flags * - * Equivalent to calling @ref ImageView(PixelStorage, U, const VectorTypeFor&, Containers::ArrayView) + * Equivalent to calling @ref ImageView(PixelStorage, U, const VectorTypeFor&, Containers::ArrayView, ImageFlags) * with default-constructed @ref PixelStorage. */ - template explicit ImageView(U format, const VectorTypeFor& size, Containers::ArrayView data) noexcept: ImageView{{}, format, size, data} {} + template explicit ImageView(U format, const VectorTypeFor& size, Containers::ArrayView data, ImageFlags flags = {}) noexcept: ImageView{{}, format, size, data, flags} {} /** * @brief Construct an empty view with implementation-specific pixel format @@ -320,57 +339,67 @@ template class ImageView { * @param format Format of pixel data * @param formatExtra Additional pixel format specifier * @param size Image size + * @param flags Image layout flags * * Uses ADL to find a corresponding @cpp pixelFormatSize(T, U) @ce - * overload, then calls @ref ImageView(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&) + * overload, then calls @ref ImageView(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, ImageFlags) * with calculated pixel size. * * Data pointer is set to @cpp nullptr @ce, call @ref setData() to * assign a memory view to the image. */ - template explicit ImageView(PixelStorage storage, U format, V formatExtra, const VectorTypeFor& size) noexcept; + template explicit ImageView(PixelStorage storage, U format, V formatExtra, const VectorTypeFor& size, ImageFlags flags = {}) noexcept; /** * @brief Construct an empty view with implementation-specific pixel format * @param storage Storage of pixel data * @param format Format of pixel data * @param size Image size + * @param flags Image layout flags * * Uses ADL to find a corresponding @cpp pixelFormatSize(T) @ce - * overload, then calls @ref ImageView(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&) + * overload, then calls @ref ImageView(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, ImageFlags) * with calculated pixel size and @p formatExtra set to @cpp 0 @ce. * * Data pointer is set to @cpp nullptr @ce, call @ref setData() to * assign a memory view to the image. */ - template explicit ImageView(PixelStorage storage, U format, const VectorTypeFor& size) noexcept; + template explicit ImageView(PixelStorage storage, U format, const VectorTypeFor& size, ImageFlags flags = {}) noexcept; /** * @brief Construct an empty view with implementation-specific pixel format * @param format Format of pixel data * @param formatExtra Additional pixel format specifier * @param size Image size + * @param flags Image layout flags * - * Equivalent to calling @ref ImageView(PixelStorage, U, V, const VectorTypeFor&, Containers::ArrayView) + * Equivalent to calling @ref ImageView(PixelStorage, U, V, const VectorTypeFor&, Containers::ArrayView, ImageFlags) * with default-constructed @ref PixelStorage. */ - template explicit ImageView(U format, V formatExtra, const VectorTypeFor& size) noexcept: ImageView{{}, format, formatExtra, size} {} + template explicit ImageView(U format, V formatExtra, const VectorTypeFor& size, ImageFlags flags = {}) noexcept: ImageView{{}, format, formatExtra, size, flags} {} /** * @brief Construct an empty view with implementation-specific pixel format * @param format Format of pixel data * @param size Image size + * @param flags Image layout flags * - * Equivalent to calling @ref ImageView(PixelStorage, U, const VectorTypeFor&) + * Equivalent to calling @ref ImageView(PixelStorage, U, const VectorTypeFor&, ImageFlags) * with default-constructed @ref PixelStorage. */ - template explicit ImageView(U format, const VectorTypeFor& size) noexcept: ImageView{{}, format, size} {} + template explicit ImageView(U format, const VectorTypeFor& size, ImageFlags flags = {}) noexcept: ImageView{{}, format, size, flags} {} /** * @brief Construct from a view of lower dimension count * @m_since{2019,10} + * + * Size in the new dimension(s) is set to @cpp 1 @ce. Original image + * flags are preserved, except for @ref ImageFlag2D::Array when + * constructing a 3D image from a 2D image (i.e., a 1D array image), as + * there's no concept of 2D arrays of 1D images. Use the @p flags + * parameter to add arbitrary other flags. */ - template::type> /*implicit*/ ImageView(const ImageView& other) noexcept; + template::type> /*implicit*/ ImageView(const ImageView& other, ImageFlags flags = {}) noexcept; /** * @brief Convert a mutable view to a const one @@ -378,6 +407,12 @@ template class ImageView { */ template::value && !std::is_const::value>::type> /*implicit*/ ImageView(const ImageView& other) noexcept; + /** + * @brief Layout flags + * @m_since_latest + */ + ImageFlags flags() const { return _flags; } + /** @brief Storage of pixel data */ PixelStorage storage() const { return _storage; } @@ -484,6 +519,7 @@ template class ImageView { PixelFormat _format; UnsignedInt _formatExtra; UnsignedInt _pixelSize; + ImageFlags _flags; VectorTypeFor _size; Containers::ArrayView _data; }; @@ -668,40 +704,49 @@ template class CompressedImageView { * @param format Format of compressed pixel data * @param size Image size * @param data Image data + * @param flags Image layout flags + * + * For a 3D image, if @p flags contain @ref ImageFlag3D::CubeMap, the + * @p size is expected to match its restrictions. */ - explicit CompressedImageView(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor& size, Containers::ArrayView data) noexcept; + explicit CompressedImageView(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor& size, Containers::ArrayView data, ImageFlags flags = {}) noexcept; /** * @brief Constructor * @param format Format of compressed pixel data * @param size Image size * @param data Image data + * @param flags Image layout flags * - * Equivalent to calling @ref CompressedImageView(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, Containers::ArrayView) + * Equivalent to calling @ref CompressedImageView(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, Containers::ArrayView, ImageFlags) * with default-constructed @ref CompressedPixelStorage. */ - explicit CompressedImageView(CompressedPixelFormat format, const VectorTypeFor& size, Containers::ArrayView data) noexcept: CompressedImageView{{}, format, size, data} {} + explicit CompressedImageView(CompressedPixelFormat format, const VectorTypeFor& size, Containers::ArrayView data, ImageFlags flags = {}) noexcept: CompressedImageView{{}, format, size, data, flags} {} /** * @brief Construct an empty view * @param storage Storage of compressed pixel data * @param format Format of compressed pixel data * @param size Image size + * @param flags Image layout flags * * Data pointer is set to @cpp nullptr @ce, call @ref setData() to - * assign a memory view to the image. + * assign a memory view to the image. For a 3D image, if @p flags + * contain @ref ImageFlag3D::CubeMap, the @p size is expected to match + * its restrictions. */ - explicit CompressedImageView(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor& size) noexcept; + explicit CompressedImageView(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor& size, ImageFlags flags = {}) noexcept; /** * @brief Construct an empty view * @param format Format of compressed pixel data * @param size Image size + * @param flags Image layout flags * - * Equivalent to calling @ref CompressedImageView(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&) + * Equivalent to calling @ref CompressedImageView(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, ImageFlags) * with default-constructed @ref CompressedPixelStorage. */ - explicit CompressedImageView(CompressedPixelFormat format, const VectorTypeFor& size) noexcept: CompressedImageView{{}, format, size} {} + explicit CompressedImageView(CompressedPixelFormat format, const VectorTypeFor& size, ImageFlags flags = {}) noexcept: CompressedImageView{{}, format, size, flags} {} /** * @brief Construct an image view with implementation-specific format @@ -709,51 +754,67 @@ template class CompressedImageView { * @param format Format of compressed pixel data * @param size Image size * @param data Image data + * @param flags Image layout flags * * Uses @ref compressedPixelFormatWrap() internally to convert * @p format to @ref CompressedPixelFormat. + * + * For a 3D image, if @p flags contain @ref ImageFlag3D::CubeMap, the + * @p size is expected to match its restrictions. */ - template explicit CompressedImageView(CompressedPixelStorage storage, U format, const VectorTypeFor& size, Containers::ArrayView data) noexcept; + template explicit CompressedImageView(CompressedPixelStorage storage, U format, const VectorTypeFor& size, Containers::ArrayView data, ImageFlags flags = {}) noexcept; /** * @brief Construct an image view with implementation-specific format * @param format Format of compressed pixel data * @param size Image size * @param data Image data + * @param flags Image layout flags * - * Equivalent to calling @ref CompressedImageView(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, Containers::ArrayView) + * Equivalent to calling @ref CompressedImageView(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, Containers::ArrayView, ImageFlags) * with default-constructed @ref CompressedPixelStorage. */ - template explicit CompressedImageView(U format, const VectorTypeFor& size, Containers::ArrayView data) noexcept: CompressedImageView{{}, format, size, data} {} + template explicit CompressedImageView(U format, const VectorTypeFor& size, Containers::ArrayView data, ImageFlags flags = {}) noexcept: CompressedImageView{{}, format, size, data, flags} {} /** * @brief Construct an empty view with implementation-specific format * @param storage Storage of compressed pixel data * @param format Format of compressed pixel data * @param size Image size + * @param flags Image layout flags * * Uses @ref compressedPixelFormatWrap() internally to convert - * @p format to @ref CompressedPixelFormat. Data pointer is set to - * @cpp nullptr @ce, call @ref setData() to assign a memory view to the - * image. + * @p format to @ref CompressedPixelFormat. + * + * Data pointer is set to @cpp nullptr @ce, call @ref setData() to + * assign a memory view to the image. For a 3D image, if @p flags + * contain @ref ImageFlag3D::CubeMap, the @p size is expected to match + * its restrictions. */ - template explicit CompressedImageView(CompressedPixelStorage storage, U format, const VectorTypeFor& size) noexcept; + template explicit CompressedImageView(CompressedPixelStorage storage, U format, const VectorTypeFor& size, ImageFlags flags = {}) noexcept; /** * @brief Construct an empty view with implementation-specific format * @param format Format of compressed pixel data * @param size Image size + * @param flags Image layout flags * - * Equivalent to calling @ref CompressedImageView(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&) + * Equivalent to calling @ref CompressedImageView(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, ImageFlags) * with default-constructed @ref CompressedPixelStorage. */ - template explicit CompressedImageView(U format, const VectorTypeFor& size) noexcept: CompressedImageView{{}, format, size} {} + template explicit CompressedImageView(U format, const VectorTypeFor& size, ImageFlags flags = {}) noexcept: CompressedImageView{{}, format, size, flags} {} /** * @brief Construct from a view of lower dimension count * @m_since{2019,10} + * + * Size in the new dimension(s) is set to @cpp 1 @ce. Original image + * flags are preserved, except for @ref ImageFlag2D::Array when + * constructing a 3D image from a 2D image (i.e., a 1D array image), as + * there's no concept of 2D arrays of 1D images. Use the @p flags + * parameter to add arbitrary other flags. */ - template::type> /*implicit*/ CompressedImageView(const CompressedImageView& other) noexcept; + template::type> /*implicit*/ CompressedImageView(const CompressedImageView& other, ImageFlags flags = {}) noexcept; /** * @brief Convert a mutable view to a const one @@ -761,6 +822,12 @@ template class CompressedImageView { */ template::value && !std::is_const::value>::type> /*implicit*/ CompressedImageView(const CompressedImageView& other) noexcept; + /** + * @brief Layout flags + * @m_since_latest + */ + ImageFlags flags() const { return _flags; } + /** @brief Storage of compressed pixel data */ CompressedPixelStorage storage() const { return _storage; } @@ -817,11 +884,12 @@ template class CompressedImageView { /* To be made public once block size and block data size are stored together with the image */ - explicit CompressedImageView(CompressedPixelStorage storage, UnsignedInt format, const VectorTypeFor& size, Containers::ArrayView data) noexcept; - explicit CompressedImageView(CompressedPixelStorage storage, UnsignedInt format, const VectorTypeFor& size) noexcept; + explicit CompressedImageView(CompressedPixelStorage storage, UnsignedInt format, const VectorTypeFor& size, Containers::ArrayView data, ImageFlags flags) noexcept; + explicit CompressedImageView(CompressedPixelStorage storage, UnsignedInt format, const VectorTypeFor& size, ImageFlags flags) noexcept; CompressedPixelStorage _storage; CompressedPixelFormat _format; + ImageFlags _flags; VectorTypeFor _size; Containers::ArrayView _data; }; @@ -899,47 +967,61 @@ typedef BasicMutableCompressedImageView<2> MutableCompressedImageView2D; */ typedef BasicMutableCompressedImageView<3> MutableCompressedImageView3D; -template template inline ImageView::ImageView(const PixelStorage storage, const U format, const V formatExtra, const VectorTypeFor& size, const Containers::ArrayView data) noexcept: ImageView{storage, UnsignedInt(format), UnsignedInt(formatExtra), Implementation::pixelFormatSizeAdl(format, formatExtra), size, data} { +template template inline ImageView::ImageView(const PixelStorage storage, const U format, const V formatExtra, const VectorTypeFor& size, const Containers::ArrayView data, const ImageFlags flags) noexcept: ImageView{storage, UnsignedInt(format), UnsignedInt(formatExtra), Implementation::pixelFormatSizeAdl(format, formatExtra), size, data, flags} { static_assert(sizeof(T) <= 4 && sizeof(U) <= 4, "format types larger than 32bits are not supported"); } -template template inline ImageView::ImageView(const PixelStorage storage, const U format, const VectorTypeFor& size, const Containers::ArrayView data) noexcept: ImageView{storage, UnsignedInt(format), {}, Implementation::pixelFormatSizeAdl(format), size, data} { +template template inline ImageView::ImageView(const PixelStorage storage, const U format, const VectorTypeFor& size, const Containers::ArrayView data, const ImageFlags flags) noexcept: ImageView{storage, UnsignedInt(format), {}, Implementation::pixelFormatSizeAdl(format), size, data, flags} { static_assert(sizeof(U) <= 4, "format types larger than 32bits are not supported"); } -template template inline ImageView::ImageView(const PixelStorage storage, const U format, const V formatExtra, const VectorTypeFor& size) noexcept: ImageView{storage, UnsignedInt(format), UnsignedInt(formatExtra), Implementation::pixelFormatSizeAdl(format, formatExtra), size} { +template template inline ImageView::ImageView(const PixelStorage storage, const U format, const V formatExtra, const VectorTypeFor& size, const ImageFlags flags) noexcept: ImageView{storage, UnsignedInt(format), UnsignedInt(formatExtra), Implementation::pixelFormatSizeAdl(format, formatExtra), size, flags} { static_assert(sizeof(U) <= 4 && sizeof(U) <= 4, "format types larger than 32bits are not supported"); } -template template inline ImageView::ImageView(const PixelStorage storage, const U format, const VectorTypeFor& size) noexcept: ImageView{storage, UnsignedInt(format), {}, Implementation::pixelFormatSizeAdl(format), size} { +template template inline ImageView::ImageView(const PixelStorage storage, const U format, const VectorTypeFor& size, const ImageFlags flags) noexcept: ImageView{storage, UnsignedInt(format), {}, Implementation::pixelFormatSizeAdl(format), size, flags} { static_assert(sizeof(U) <= 4, "format types larger than 32bits are not supported"); } #ifndef DOXYGEN_GENERATING_OUTPUT /* it complains otherwise. why? don't know, don't want to know */ -template template ImageView::ImageView(const ImageView& other) noexcept: _storage{other._storage}, _format{other._format}, _formatExtra{other._formatExtra}, _pixelSize{other._pixelSize}, _size{Math::Vector::pad(other._size, 1)}, _data{other._data} {} +template template ImageView::ImageView(const ImageView& other, const ImageFlags flags) noexcept: + _storage{other._storage}, + _format{other._format}, + _formatExtra{other._formatExtra}, + _pixelSize{other._pixelSize}, + /* Removing the Array bit and transferring the rest, as documented */ + _flags{ImageFlag(UnsignedShort(other._flags)&~UnsignedShort(ImageFlag2D::Array))|flags}, + _size{Math::Vector::pad(other._size, 1)}, + _data{other._data} {} #endif -template template ImageView::ImageView(const ImageView& other) noexcept: _storage{other._storage}, _format{other._format}, _formatExtra{other._formatExtra}, _pixelSize{other._pixelSize}, _size{other._size}, _data{other._data} {} +template template ImageView::ImageView(const ImageView& other) noexcept: _storage{other._storage}, _format{other._format}, _formatExtra{other._formatExtra}, _pixelSize{other._pixelSize}, _flags{other._flags}, _size{other._size}, _data{other._data} {} -template template inline CompressedImageView::CompressedImageView(const CompressedPixelStorage storage, const U format, const VectorTypeFor& size, const Containers::ArrayView data) noexcept: CompressedImageView{storage, UnsignedInt(format), size, data} { +template template inline CompressedImageView::CompressedImageView(const CompressedPixelStorage storage, const U format, const VectorTypeFor& size, const Containers::ArrayView data, const ImageFlags flags) noexcept: CompressedImageView{storage, UnsignedInt(format), size, data, flags} { static_assert(sizeof(U) <= 4, "format types larger than 32bits are not supported"); } -template template inline CompressedImageView::CompressedImageView(const CompressedPixelStorage storage, const U format, const VectorTypeFor& size) noexcept: CompressedImageView{storage, UnsignedInt(format), size} { +template template inline CompressedImageView::CompressedImageView(const CompressedPixelStorage storage, const U format, const VectorTypeFor& size, const ImageFlags flags) noexcept: CompressedImageView{storage, UnsignedInt(format), size, flags} { static_assert(sizeof(U) <= 4, "format types larger than 32bits are not supported"); } #ifndef DOXYGEN_GENERATING_OUTPUT /* it complains otherwise. why? don't know, don't want to know */ -template template CompressedImageView::CompressedImageView(const CompressedImageView& other) noexcept: _storage{other._storage}, _format{other._format}, _size{Math::Vector::pad(other._size, 1)}, _data{other._data} {} +template template CompressedImageView::CompressedImageView(const CompressedImageView& other, const ImageFlags flags) noexcept: + _storage{other._storage}, + _format{other._format}, + /* Removing the Array bit and transferring the rest, as documented */ + _flags{ImageFlag(UnsignedShort(other._flags)&~UnsignedShort(ImageFlag2D::Array))|flags}, + _size{Math::Vector::pad(other._size, 1)}, + _data{other._data} {} #endif -template template CompressedImageView::CompressedImageView(const CompressedImageView& other) noexcept: _storage{other._storage}, _format{other._format}, _size{other._size}, _data{other._data} {} +template template CompressedImageView::CompressedImageView(const CompressedImageView& other) noexcept: _storage{other._storage}, _format{other._format}, _flags{other._flags}, _size{other._size}, _data{other._data} {} } diff --git a/src/Magnum/Implementation/ImageProperties.h b/src/Magnum/Implementation/ImageProperties.h index dfbc7c1d79..6dd1c901da 100644 --- a/src/Magnum/Implementation/ImageProperties.h +++ b/src/Magnum/Implementation/ImageProperties.h @@ -29,10 +29,27 @@ #include #include "Magnum/Magnum.h" +#ifndef CORRADE_NO_ASSERT +#include "Magnum/ImageFlags.h" +#endif #include "Magnum/DimensionTraits.h" namespace Magnum { namespace Implementation { +/* Used in *Image and Compressed*Image constructors */ +#ifndef CORRADE_NO_ASSERT +inline void checkImageFlagsForSize(const char*, const ImageFlags1D, const Math::Vector<1, Int>&) {} +inline void checkImageFlagsForSize(const char*, const ImageFlags2D, const Vector2i&) {} +inline void checkImageFlagsForSize(const char* const prefix, const ImageFlags3D flags, const Vector3i& size) { + CORRADE_ASSERT(!(flags & ImageFlag3D::CubeMap) || size.x() == size.y(), + prefix << "expected square faces for a cube map, got" << Debug::packed << size.xy(), ); + CORRADE_ASSERT(!(flags & ImageFlag3D::CubeMap) || (flags & ImageFlag3D::Array) || size.z() == 6, + prefix << "expected exactly 6 faces for a cube map, got" << size.z(), ); + CORRADE_ASSERT(!(flags >= (ImageFlag3D::CubeMap|ImageFlag3D::Array)) || size.z() % 6 == 0, + prefix << "expected a multiple of 6 faces for a cube map array, got" << size.z(), ); +} +#endif + /* Used in *Image::dataProperties() */ template std::pair, Math::Vector> imageDataProperties(const T& image) { std::pair, Math::Vector3> dataProperties = image.storage().dataProperties(image.pixelSize(), Vector3i::pad(image.size(), 1)); diff --git a/src/Magnum/Magnum.h b/src/Magnum/Magnum.h index f781979c11..c9e14412f8 100644 --- a/src/Magnum/Magnum.h +++ b/src/Magnum/Magnum.h @@ -1226,6 +1226,13 @@ template class CORRADE_DEPRECATED("use Math::Vector3 or Containers::Arr enum class InputFileCallbackPolicy: UnsignedByte; +enum class ImageFlag1D: UnsignedShort; +enum class ImageFlag2D: UnsignedShort; +enum class ImageFlag3D: UnsignedShort; +typedef Containers::EnumSet ImageFlags1D; +typedef Containers::EnumSet ImageFlags2D; +typedef Containers::EnumSet ImageFlags3D; + template class Image; typedef Image<1> Image1D; typedef Image<2> Image2D; diff --git a/src/Magnum/Test/CMakeLists.txt b/src/Magnum/Test/CMakeLists.txt index ccf12eb301..cab58ee1a5 100644 --- a/src/Magnum/Test/CMakeLists.txt +++ b/src/Magnum/Test/CMakeLists.txt @@ -29,6 +29,7 @@ set(CMAKE_FOLDER "Magnum/Test") corrade_add_test(FileCallbackTest FileCallbackTest.cpp LIBRARIES Magnum) corrade_add_test(ImageTest ImageTest.cpp LIBRARIES MagnumTestLib) +corrade_add_test(ImageFlagsTest ImageFlagsTest.cpp LIBRARIES Magnum) corrade_add_test(ImageViewTest ImageViewTest.cpp LIBRARIES MagnumTestLib) corrade_add_test(MeshTest MeshTest.cpp LIBRARIES MagnumTestLib) corrade_add_test(PixelFormatTest PixelFormatTest.cpp LIBRARIES MagnumTestLib) diff --git a/src/Magnum/Test/ImageFlagsTest.cpp b/src/Magnum/Test/ImageFlagsTest.cpp new file mode 100644 index 0000000000..9d03d6d0df --- /dev/null +++ b/src/Magnum/Test/ImageFlagsTest.cpp @@ -0,0 +1,157 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021, 2022 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include + +#include "Magnum/ImageFlags.h" + +namespace Magnum { namespace Test { namespace { + +struct ImageFlagsTest: TestSuite::Tester { + explicit ImageFlagsTest(); + + void matchingValues(); + + void debugFlag1D(); + void debugFlag2D(); + void debugFlag3D(); + void debugFlag1DPacked(); + void debugFlag2DPacked(); + void debugFlag3DPacked(); + + void debugFlags1D(); + void debugFlags2D(); + void debugFlags3D(); + void debugFlags1DPacked(); + void debugFlags2DPacked(); + void debugFlags3DPacked(); +}; + +ImageFlagsTest::ImageFlagsTest() { + addTests({&ImageFlagsTest::matchingValues, + + &ImageFlagsTest::debugFlag1D, + &ImageFlagsTest::debugFlag2D, + &ImageFlagsTest::debugFlag3D, + &ImageFlagsTest::debugFlag1DPacked, + &ImageFlagsTest::debugFlag2DPacked, + &ImageFlagsTest::debugFlag3DPacked, + + &ImageFlagsTest::debugFlags1D, + &ImageFlagsTest::debugFlags2D, + &ImageFlagsTest::debugFlags3D, + &ImageFlagsTest::debugFlags1DPacked, + &ImageFlagsTest::debugFlags2DPacked, + &ImageFlagsTest::debugFlags3DPacked}); +} + +void ImageFlagsTest::matchingValues() { + CORRADE_COMPARE(UnsignedShort(ImageFlag3D::Array), UnsignedShort(ImageFlag2D::Array)); +} + +void ImageFlagsTest::debugFlag1D() { + std::ostringstream out; + /** @todo use a real flag once it exists */ + Debug{&out} << ImageFlag1D(0xcafe); + CORRADE_COMPARE(out.str(), "ImageFlag1D(0xcafe)\n"); +} + +void ImageFlagsTest::debugFlag2D() { + std::ostringstream out; + Debug{&out} << ImageFlag2D::Array << ImageFlag2D(0xcafe); + CORRADE_COMPARE(out.str(), "ImageFlag2D::Array ImageFlag2D(0xcafe)\n"); +} + +void ImageFlagsTest::debugFlag3D() { + std::ostringstream out; + Debug{&out} << ImageFlag3D::CubeMap << ImageFlag3D(0xcafe); + CORRADE_COMPARE(out.str(), "ImageFlag3D::CubeMap ImageFlag3D(0xcafe)\n"); +} + +void ImageFlagsTest::debugFlag1DPacked() { + std::ostringstream out; + /* Last is not packed, ones before should not make any flags persistent */ + /** @todo use real flags once they exist */ + Debug{&out} << Debug::packed << ImageFlag1D(0xcafe) << ImageFlag1D(0xbeef); + CORRADE_COMPARE(out.str(), "0xcafe ImageFlag1D(0xbeef)\n"); +} + +void ImageFlagsTest::debugFlag2DPacked() { + std::ostringstream out; + /* Last is not packed, ones before should not make any flags persistent */ + Debug{&out} << Debug::packed << ImageFlag2D::Array << Debug::packed << ImageFlag2D(0xcafe) << ImageFlag2D(0xbeef); + CORRADE_COMPARE(out.str(), "Array 0xcafe ImageFlag2D(0xbeef)\n"); +} + +void ImageFlagsTest::debugFlag3DPacked() { + std::ostringstream out; + /* Last is not packed, ones before should not make any flags persistent */ + Debug{&out} << Debug::packed << ImageFlag3D::CubeMap << Debug::packed << ImageFlag3D(0xcafe) << ImageFlag3D(0xbeef); + CORRADE_COMPARE(out.str(), "CubeMap 0xcafe ImageFlag3D(0xbeef)\n"); +} + +void ImageFlagsTest::debugFlags1D() { + std::ostringstream out; + /** @todo use real flags once they exist */ + Debug{&out} << (ImageFlag1D{}|ImageFlag1D(0xcafe)) << ImageFlags1D{}; + CORRADE_COMPARE(out.str(), "ImageFlag1D(0xcafe) ImageFlags1D{}\n"); +} + +void ImageFlagsTest::debugFlags2D() { + std::ostringstream out; + Debug{&out} << (ImageFlag2D::Array|ImageFlag2D(0xcafe)) << ImageFlags2D{}; + CORRADE_COMPARE(out.str(), "ImageFlag2D::Array|ImageFlag2D(0xcafe) ImageFlags2D{}\n"); +} + +void ImageFlagsTest::debugFlags3D() { + std::ostringstream out; + Debug{&out} << (ImageFlag3D::Array|ImageFlag3D::CubeMap |ImageFlag3D(0xcaf0)) << ImageFlags3D{}; + CORRADE_COMPARE(out.str(), "ImageFlag3D::Array|ImageFlag3D::CubeMap|ImageFlag3D(0xcaf0) ImageFlags3D{}\n"); +} + +void ImageFlagsTest::debugFlags1DPacked() { + std::ostringstream out; + /** @todo use real flags once they exist */ + Debug{&out} << Debug::packed << (ImageFlag1D{}|ImageFlag1D(0xcafe)) << Debug::packed << ImageFlags1D{} << ImageFlag1D(0xbeef); + CORRADE_COMPARE(out.str(), "0xcafe {} ImageFlag1D(0xbeef)\n"); +} + +void ImageFlagsTest::debugFlags2DPacked() { + std::ostringstream out; + Debug{&out} << Debug::packed << (ImageFlag2D::Array|ImageFlag2D(0xcaf0)) << Debug::packed << ImageFlags2D{} << ImageFlag2D(0xbeef); + CORRADE_COMPARE(out.str(), "Array|0xcaf0 {} ImageFlag2D(0xbeef)\n"); +} + +void ImageFlagsTest::debugFlags3DPacked() { + std::ostringstream out; + Debug{&out} << Debug::packed << (ImageFlag3D::Array|ImageFlag3D::CubeMap |ImageFlag3D(0xcaf0)) << Debug::packed << ImageFlags3D{} << ImageFlag3D(0xbeef); + CORRADE_COMPARE(out.str(), "Array|CubeMap|0xcaf0 {} ImageFlag3D(0xbeef)\n"); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Test::ImageFlagsTest) diff --git a/src/Magnum/Test/ImageTest.cpp b/src/Magnum/Test/ImageTest.cpp index f98ebb3bba..14015261c6 100644 --- a/src/Magnum/Test/ImageTest.cpp +++ b/src/Magnum/Test/ImageTest.cpp @@ -51,7 +51,9 @@ struct ImageTest: TestSuite::Tester { void constructCompressedImplementationSpecific(); void constructInvalidSize(); + void constructInvalidCubeMap(); void constructCompressedInvalidSize(); + void constructCompressedInvalidCubeMap(); void constructCopy(); void constructCopyCompressed(); @@ -106,7 +108,9 @@ ImageTest::ImageTest() { &ImageTest::constructCompressedImplementationSpecific, &ImageTest::constructInvalidSize, + &ImageTest::constructInvalidCubeMap, &ImageTest::constructCompressedInvalidSize, + &ImageTest::constructCompressedInvalidCubeMap, &ImageTest::constructCopy, &ImageTest::constructCopyCompressed, @@ -179,8 +183,9 @@ namespace Vk { void ImageTest::constructGeneric() { { auto data = new char[4*4]; - Image2D a{PixelFormat::RGBA8Unorm, {1, 3}, Containers::Array{data, 4*4}}; + Image2D a{PixelFormat::RGBA8Unorm, {1, 3}, Containers::Array{data, 4*4}, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().alignment(), 4); CORRADE_COMPARE(a.format(), PixelFormat::RGBA8Unorm); CORRADE_COMPARE(a.formatExtra(), 0); @@ -191,8 +196,9 @@ void ImageTest::constructGeneric() { } { auto data = new char[3*2]; Image2D a{PixelStorage{}.setAlignment(1), - PixelFormat::R16UI, {1, 3}, Containers::Array{data, 3*2}}; + PixelFormat::R16UI, {1, 3}, Containers::Array{data, 3*2}, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), PixelFormat::R16UI); CORRADE_COMPARE(a.formatExtra(), 0); @@ -207,6 +213,7 @@ void ImageTest::constructGenericPlaceholder() { { Image2D a{PixelFormat::RG32F}; + CORRADE_COMPARE(a.flags(), ImageFlags2D{}); CORRADE_COMPARE(a.storage().alignment(), 4); CORRADE_COMPARE(a.format(), PixelFormat::RG32F); CORRADE_COMPARE(a.formatExtra(), 0); @@ -217,6 +224,7 @@ void ImageTest::constructGenericPlaceholder() { Image2D a{PixelStorage{}.setAlignment(1), PixelFormat::RGB16F}; + CORRADE_COMPARE(a.flags(), ImageFlags2D{}); CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), PixelFormat::RGB16F); CORRADE_COMPARE(a.formatExtra(), 0); @@ -230,8 +238,9 @@ void ImageTest::constructImplementationSpecific() { /* Single format */ { auto data = new char[3*12]; - Image2D a{Vk::PixelFormat::R32G32B32F, {1, 3}, Containers::Array{data, 3*12}}; + Image2D a{Vk::PixelFormat::R32G32B32F, {1, 3}, Containers::Array{data, 3*12}, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().alignment(), 4); CORRADE_COMPARE(a.format(), pixelFormatWrap(Vk::PixelFormat::R32G32B32F)); CORRADE_COMPARE(a.formatExtra(), 0); @@ -242,8 +251,9 @@ void ImageTest::constructImplementationSpecific() { } { auto data = new char[3*12]; Image2D a{PixelStorage{}.setAlignment(1), - Vk::PixelFormat::R32G32B32F, {1, 3}, Containers::Array{data, 3*12}}; + Vk::PixelFormat::R32G32B32F, {1, 3}, Containers::Array{data, 3*12}, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), pixelFormatWrap(Vk::PixelFormat::R32G32B32F)); CORRADE_COMPARE(a.formatExtra(), 0); @@ -256,8 +266,9 @@ void ImageTest::constructImplementationSpecific() { /* Format + extra */ { auto data = new char[3*8]; - Image2D a{GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, Containers::Array{data, 3*8}}; + Image2D a{GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, Containers::Array{data, 3*8}, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().alignment(), 4); CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(a.formatExtra(), UnsignedInt(GL::PixelType::UnsignedShort)); @@ -268,8 +279,9 @@ void ImageTest::constructImplementationSpecific() { } { auto data = new char[3*6]; Image2D a{PixelStorage{}.setAlignment(1), - GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, Containers::Array{data, 3*6}}; + GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, Containers::Array{data, 3*6}, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(a.formatExtra(), UnsignedInt(GL::PixelType::UnsignedShort)); CORRADE_COMPARE(a.pixelSize(), 6); @@ -281,8 +293,9 @@ void ImageTest::constructImplementationSpecific() { /* Manual pixel size */ { auto data = new char[3*6]; - Image2D a{PixelStorage{}.setAlignment(1), 666, 1337, 6, {1, 3}, Containers::Array{data, 3*6}}; + Image2D a{PixelStorage{}.setAlignment(1), 666, 1337, 6, {1, 3}, Containers::Array{data, 3*6}, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(a.formatExtra(), UnsignedInt(GL::PixelType::UnsignedShort)); @@ -298,6 +311,7 @@ void ImageTest::constructImplementationSpecificPlaceholder() { { Image2D a{Vk::PixelFormat::R32G32B32F}; + CORRADE_COMPARE(a.flags(), ImageFlags2D{}); CORRADE_COMPARE(a.storage().alignment(), 4); CORRADE_COMPARE(a.format(), pixelFormatWrap(Vk::PixelFormat::R32G32B32F)); CORRADE_COMPARE(a.formatExtra(), 0); @@ -308,6 +322,7 @@ void ImageTest::constructImplementationSpecificPlaceholder() { Image2D a{PixelStorage{}.setAlignment(1), Vk::PixelFormat::R32G32B32F}; + CORRADE_COMPARE(a.flags(), ImageFlags2D{}); CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), pixelFormatWrap(Vk::PixelFormat::R32G32B32F)); CORRADE_COMPARE(a.formatExtra(), 0); @@ -320,6 +335,7 @@ void ImageTest::constructImplementationSpecificPlaceholder() { { Image2D a{GL::PixelFormat::RGB, GL::PixelType::UnsignedShort}; + CORRADE_COMPARE(a.flags(), ImageFlags2D{}); CORRADE_COMPARE(a.storage().alignment(), 4); CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(a.formatExtra(), UnsignedInt(GL::PixelType::UnsignedShort)); @@ -330,6 +346,7 @@ void ImageTest::constructImplementationSpecificPlaceholder() { Image2D a{PixelStorage{}.setAlignment(1), GL::PixelFormat::RGB, GL::PixelType::UnsignedShort}; + CORRADE_COMPARE(a.flags(), ImageFlags2D{}); CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(a.formatExtra(), UnsignedInt(GL::PixelType::UnsignedShort)); CORRADE_COMPARE(a.pixelSize(), 6); @@ -341,6 +358,7 @@ void ImageTest::constructImplementationSpecificPlaceholder() { { Image2D a{PixelStorage{}.setAlignment(1), 666, 1337, 6}; + CORRADE_COMPARE(a.flags(), ImageFlags2D{}); CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(a.formatExtra(), UnsignedInt(GL::PixelType::UnsignedShort)); @@ -354,8 +372,9 @@ void ImageTest::constructCompressedGeneric() { { auto data = new char[8]; CompressedImage2D a{CompressedPixelFormat::Bc1RGBAUnorm, {4, 4}, - Containers::Array{data, 8}}; + Containers::Array{data, 8}, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{0}); CORRADE_COMPARE(a.format(), CompressedPixelFormat::Bc1RGBAUnorm); CORRADE_COMPARE(a.size(), (Vector2i{4, 4})); @@ -365,8 +384,9 @@ void ImageTest::constructCompressedGeneric() { auto data = new char[8]; CompressedImage2D a{CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), CompressedPixelFormat::Bc1RGBAUnorm, {4, 4}, - Containers::Array{data, 8}}; + Containers::Array{data, 8}, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(a.format(), CompressedPixelFormat::Bc1RGBAUnorm); CORRADE_COMPARE(a.size(), Vector2i(4, 4)); @@ -379,6 +399,7 @@ void ImageTest::constructCompressedGenericPlaceholder() { { CompressedImage2D a; + CORRADE_COMPARE(a.flags(), ImageFlags2D{}); CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{0}); CORRADE_COMPARE(a.format(), CompressedPixelFormat{}); CORRADE_COMPARE(a.size(), Vector2i{}); @@ -386,6 +407,7 @@ void ImageTest::constructCompressedGenericPlaceholder() { } { CompressedImage2D a{CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4})}; + CORRADE_COMPARE(a.flags(), ImageFlags2D{}); CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(a.format(), CompressedPixelFormat{}); CORRADE_COMPARE(a.size(), Vector2i{}); @@ -398,8 +420,9 @@ void ImageTest::constructCompressedImplementationSpecific() { { auto data = new char[8]; CompressedImage2D a{GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 4}, - Containers::Array{data, 8}}; + Containers::Array{data, 8}, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{0}); CORRADE_COMPARE(a.format(), compressedPixelFormatWrap(GL::CompressedPixelFormat::RGBS3tcDxt1)); CORRADE_COMPARE(a.size(), (Vector2i{4, 4})); @@ -409,8 +432,9 @@ void ImageTest::constructCompressedImplementationSpecific() { auto data = new char[8]; CompressedImage2D a{CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 4}, - Containers::Array{data, 8}}; + Containers::Array{data, 8}, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(a.format(), compressedPixelFormatWrap(GL::CompressedPixelFormat::RGBS3tcDxt1)); CORRADE_COMPARE(a.size(), (Vector2i{4, 4})); @@ -434,6 +458,24 @@ void ImageTest::constructInvalidSize() { CORRADE_COMPARE(out.str(), "Image: data too small, got 9 but expected at least 12 bytes\n"); } +void ImageTest::constructInvalidCubeMap() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + std::ostringstream out; + Error redirectError{&out}; + Image3D{PixelFormat::RGBA8Unorm, {3, 3, 5}, Containers::Array{3*3*5*4}, ImageFlag3D::CubeMap}; + Image3D{PixelFormat::RGBA8Unorm, {3, 4, 6}, Containers::Array{3*4*6*4}, ImageFlag3D::CubeMap}; + Image3D{PixelFormat::RGBA8Unorm, {3, 3, 17}, Containers::Array{3*3*17*4}, ImageFlag3D::CubeMap |ImageFlag3D::Array}; + Image3D{PixelFormat::RGBA8Unorm, {4, 3, 18}, Containers::Array{4*3*18*4}, ImageFlag3D::CubeMap |ImageFlag3D::Array}; + CORRADE_COMPARE(out.str(), + "Image: expected exactly 6 faces for a cube map, got 5\n" + "Image: expected square faces for a cube map, got {3, 4}\n" + "Image: expected a multiple of 6 faces for a cube map array, got 17\n" + "Image: expected square faces for a cube map, got {4, 3}\n"); +} + void ImageTest::constructCompressedInvalidSize() { CORRADE_EXPECT_FAIL("Size checking for compressed image data is not implemented yet."); @@ -453,6 +495,24 @@ void ImageTest::constructCompressedInvalidSize() { } } +void ImageTest::constructCompressedInvalidCubeMap() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + std::ostringstream out; + Error redirectError{&out}; + CompressedImage3D{CompressedPixelFormat::Bc1RGBAUnorm, {3, 3, 5}, Containers::Array{8*5}, ImageFlag3D::CubeMap}; + CompressedImage3D{CompressedPixelFormat::Bc1RGBAUnorm, {3, 4, 6}, Containers::Array{8*6}, ImageFlag3D::CubeMap}; + CompressedImage3D{CompressedPixelFormat::Bc1RGBAUnorm, {3, 3, 17}, Containers::Array{8*17}, ImageFlag3D::CubeMap |ImageFlag3D::Array}; + CompressedImage3D{CompressedPixelFormat::Bc1RGBAUnorm, {4, 3, 18}, Containers::Array{8*18}, ImageFlag3D::CubeMap |ImageFlag3D::Array}; + CORRADE_COMPARE(out.str(), + "CompressedImage: expected exactly 6 faces for a cube map, got 5\n" + "CompressedImage: expected square faces for a cube map, got {3, 4}\n" + "CompressedImage: expected a multiple of 6 faces for a cube map array, got 17\n" + "CompressedImage: expected square faces for a cube map, got {4, 3}\n"); +} + void ImageTest::constructCopy() { CORRADE_VERIFY(!std::is_copy_constructible{}); CORRADE_VERIFY(!std::is_copy_assignable{}); @@ -466,12 +526,13 @@ void ImageTest::constructCopyCompressed() { void ImageTest::constructMoveGeneric() { auto data = new char[3*16]; Image2D a{PixelStorage{}.setAlignment(1), - PixelFormat::RGBA32F, {1, 3}, Containers::Array{data, 3*16}}; + PixelFormat::RGBA32F, {1, 3}, Containers::Array{data, 3*16}, ImageFlag2D::Array}; Image2D b(std::move(a)); CORRADE_COMPARE(a.data(), nullptr); CORRADE_COMPARE(a.size(), Vector2i{}); + CORRADE_COMPARE(b.flags(), ImageFlag2D::Array); CORRADE_COMPARE(b.storage().alignment(), 1); CORRADE_COMPARE(b.format(), PixelFormat::RGBA32F); CORRADE_COMPARE(b.formatExtra(), 0); @@ -487,6 +548,7 @@ void ImageTest::constructMoveGeneric() { CORRADE_COMPARE(b.data(), data2); CORRADE_COMPARE(b.size(), (Vector2i{2, 6})); + CORRADE_COMPARE(c.flags(), ImageFlag2D::Array); CORRADE_COMPARE(c.storage().alignment(), 1); CORRADE_COMPARE(c.format(), PixelFormat::RGBA32F); CORRADE_COMPARE(c.formatExtra(), 0); @@ -502,12 +564,13 @@ void ImageTest::constructMoveGeneric() { void ImageTest::constructMoveImplementationSpecific() { auto data = new char[3*6]; Image2D a{PixelStorage{}.setAlignment(1), - GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, Containers::Array{data, 3*6}}; + GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, Containers::Array{data, 3*6}, ImageFlag2D::Array}; Image2D b(std::move(a)); CORRADE_COMPARE(a.data(), nullptr); CORRADE_COMPARE(a.size(), Vector2i{}); + CORRADE_COMPARE(b.flags(), ImageFlag2D::Array); CORRADE_COMPARE(b.storage().alignment(), 1); CORRADE_COMPARE(b.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(b.formatExtra(), 1337); @@ -524,6 +587,7 @@ void ImageTest::constructMoveImplementationSpecific() { CORRADE_COMPARE(b.data(), data2); CORRADE_COMPARE(b.size(), Vector2i(2, 6)); + CORRADE_COMPARE(c.flags(), ImageFlag2D::Array); CORRADE_COMPARE(c.storage().alignment(), 1); CORRADE_COMPARE(c.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(c.formatExtra(), 1337); @@ -537,12 +601,13 @@ void ImageTest::constructMoveCompressedGeneric() { auto data = new char[8]; CompressedImage2D a{ CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), - CompressedPixelFormat::Bc3RGBAUnorm, {4, 4}, Containers::Array{data, 8}}; + CompressedPixelFormat::Bc3RGBAUnorm, {4, 4}, Containers::Array{data, 8}, ImageFlag2D::Array}; CompressedImage2D b{std::move(a)}; CORRADE_COMPARE(a.data(), nullptr); CORRADE_COMPARE(a.size(), Vector2i{}); + CORRADE_COMPARE(b.flags(), ImageFlag2D::Array); CORRADE_COMPARE(b.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(b.format(), CompressedPixelFormat::Bc3RGBAUnorm); CORRADE_COMPARE(b.size(), (Vector2i{4, 4})); @@ -556,6 +621,7 @@ void ImageTest::constructMoveCompressedGeneric() { CORRADE_COMPARE(b.data(), data2); CORRADE_COMPARE(b.size(), (Vector2i{8, 4})); + CORRADE_COMPARE(c.flags(), ImageFlag2D::Array); CORRADE_COMPARE(c.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(c.format(), CompressedPixelFormat::Bc3RGBAUnorm); CORRADE_COMPARE(c.size(), (Vector2i{4, 4})); @@ -570,12 +636,13 @@ void ImageTest::constructMoveCompressedImplementationSpecific() { auto data = new char[8]; CompressedImage2D a{ CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), - GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 4}, Containers::Array{data, 8}}; + GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 4}, Containers::Array{data, 8}, ImageFlag2D::Array}; CompressedImage2D b{std::move(a)}; CORRADE_COMPARE(a.data(), nullptr); CORRADE_COMPARE(a.size(), Vector2i{}); + CORRADE_COMPARE(b.flags(), ImageFlag2D::Array); CORRADE_COMPARE(b.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(b.format(), compressedPixelFormatWrap(GL::CompressedPixelFormat::RGBS3tcDxt1)); CORRADE_COMPARE(b.size(), (Vector2i{4, 4})); @@ -589,6 +656,7 @@ void ImageTest::constructMoveCompressedImplementationSpecific() { CORRADE_COMPARE(b.data(), data2); CORRADE_COMPARE(b.size(), (Vector2i{8, 4})); + CORRADE_COMPARE(c.flags(), ImageFlag2D::Array); CORRADE_COMPARE(c.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(c.format(), compressedPixelFormatWrap(GL::CompressedPixelFormat::RGBS3tcDxt1)); CORRADE_COMPARE(c.size(), (Vector2i{4, 4})); @@ -601,9 +669,10 @@ template void ImageTest::toViewGeneric() { auto data = new char[3*4]; typename MutabilityTraits::ImageType a{PixelStorage{}.setAlignment(1), - PixelFormat::RG16I, {1, 3}, Containers::Array{data, 3*4}}; + PixelFormat::RG16I, {1, 3}, Containers::Array{data, 3*4}, ImageFlag2D::Array}; ImageView<2, T> b = a; + CORRADE_COMPARE(b.flags(), ImageFlag2D::Array); CORRADE_COMPARE(b.storage().alignment(), 1); CORRADE_COMPARE(b.format(), PixelFormat::RG16I); CORRADE_COMPARE(b.formatExtra(), 0); @@ -617,9 +686,10 @@ template void ImageTest::toViewImplementationSpecific() { auto data = new char[3*6]; typename MutabilityTraits::ImageType a{PixelStorage{}.setAlignment(1), - GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, Containers::Array{data, 3*6}}; + GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, Containers::Array{data, 3*6}, ImageFlag2D::Array}; ImageView<2, T> b = a; + CORRADE_COMPARE(b.flags(), ImageFlag2D::Array); CORRADE_COMPARE(b.storage().alignment(), 1); CORRADE_COMPARE(b.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(b.formatExtra(), 1337); @@ -634,9 +704,10 @@ template void ImageTest::toViewCompressedGeneric() { auto data = new char[8]; typename MutabilityTraits::CompressedImageType a{ CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), - CompressedPixelFormat::Bc1RGBUnorm, {4, 4}, Containers::Array{data, 8}}; + CompressedPixelFormat::Bc1RGBUnorm, {4, 4}, Containers::Array{data, 8}, ImageFlag2D::Array}; CompressedImageView<2, T> b = a; + CORRADE_COMPARE(b.flags(), ImageFlag2D::Array); CORRADE_COMPARE(b.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(b.format(), CompressedPixelFormat::Bc1RGBUnorm); CORRADE_COMPARE(b.size(), (Vector2i{4, 4})); @@ -650,9 +721,10 @@ template void ImageTest::toViewCompressedImplementationSpecific() { auto data = new char[8]; typename MutabilityTraits::CompressedImageType a{ CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), - GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 4}, Containers::Array{data, 8}}; + GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 4}, Containers::Array{data, 8}, ImageFlag2D::Array}; CompressedImageView<2, T> b = a; + CORRADE_COMPARE(b.flags(), ImageFlag2D::Array); CORRADE_COMPARE(b.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(b.format(), compressedPixelFormatWrap(GL::CompressedPixelFormat::RGBS3tcDxt1)); CORRADE_COMPARE(b.size(), (Vector2i{4, 4})); diff --git a/src/Magnum/Test/ImageViewTest.cpp b/src/Magnum/Test/ImageViewTest.cpp index a26d555808..8c7c95aafd 100644 --- a/src/Magnum/Test/ImageViewTest.cpp +++ b/src/Magnum/Test/ImageViewTest.cpp @@ -60,7 +60,9 @@ struct ImageViewTest: TestSuite::Tester { void constructNullptr(); void constructInvalidSize(); + void constructInvalidCubeMap(); void constructCompressedInvalidSize(); + void constructCompressedInvalidCubeMap(); void dataProperties(); void dataPropertiesCompressed(); @@ -113,7 +115,9 @@ ImageViewTest::ImageViewTest() { &ImageViewTest::constructNullptr, &ImageViewTest::constructInvalidSize, + &ImageViewTest::constructInvalidCubeMap, &ImageViewTest::constructCompressedInvalidSize, + &ImageViewTest::constructCompressedInvalidCubeMap, &ImageViewTest::dataProperties, &ImageViewTest::dataPropertiesCompressed, @@ -175,8 +179,9 @@ template void ImageViewTest::constructGeneric() { { T data[4*4]{}; - ImageView<2, T> a{PixelFormat::RGBA8Unorm, {1, 3}, data}; + ImageView<2, T> a{PixelFormat::RGBA8Unorm, {1, 3}, data, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().alignment(), 4); CORRADE_COMPARE(a.format(), PixelFormat::RGBA8Unorm); CORRADE_COMPARE(a.formatExtra(), 0); @@ -187,8 +192,9 @@ template void ImageViewTest::constructGeneric() { } { T data[3*2]{}; ImageView<2, T> a{PixelStorage{}.setAlignment(1), - PixelFormat::R16UI, {1, 3}, data}; + PixelFormat::R16UI, {1, 3}, data, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), PixelFormat::R16UI); CORRADE_COMPARE(a.formatExtra(), 0); @@ -203,8 +209,9 @@ template void ImageViewTest::constructGenericEmpty() { setTestCaseTemplateName(MutabilityTraits::name()); { - ImageView<2, T> a{PixelFormat::RG32F, {2, 6}}; + ImageView<2, T> a{PixelFormat::RG32F, {2, 6}, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().alignment(), 4); CORRADE_COMPARE(a.format(), PixelFormat::RG32F); CORRADE_COMPARE(a.formatExtra(), 0); @@ -213,8 +220,9 @@ template void ImageViewTest::constructGenericEmpty() { CORRADE_COMPARE(a.data(), static_cast(nullptr)); } { ImageView<2, T> a{PixelStorage{}.setAlignment(1), - PixelFormat::RGB16F, {8, 3}}; + PixelFormat::RGB16F, {8, 3}, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), PixelFormat::RGB16F); CORRADE_COMPARE(a.formatExtra(), 0); @@ -230,8 +238,9 @@ template void ImageViewTest::constructImplementationSpecific() { /* Single format */ { T data[3*12]{}; - ImageView<2, T> a{Vk::PixelFormat::R32G32B32F, {1, 3}, data}; + ImageView<2, T> a{Vk::PixelFormat::R32G32B32F, {1, 3}, data, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().alignment(), 4); CORRADE_COMPARE(a.format(), pixelFormatWrap(Vk::PixelFormat::R32G32B32F)); CORRADE_COMPARE(a.formatExtra(), 0); @@ -242,8 +251,9 @@ template void ImageViewTest::constructImplementationSpecific() { } { T data[3*12]{}; ImageView<2, T> a{PixelStorage{}.setAlignment(1), - Vk::PixelFormat::R32G32B32F, {1, 3}, data}; + Vk::PixelFormat::R32G32B32F, {1, 3}, data, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), pixelFormatWrap(Vk::PixelFormat::R32G32B32F)); CORRADE_COMPARE(a.formatExtra(), 0); @@ -256,8 +266,9 @@ template void ImageViewTest::constructImplementationSpecific() { /* Format + extra */ { T data[3*8]{}; - ImageView<2, T> a{GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, data}; + ImageView<2, T> a{GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, data, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().alignment(), 4); CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(a.formatExtra(), UnsignedInt(GL::PixelType::UnsignedShort)); @@ -268,8 +279,9 @@ template void ImageViewTest::constructImplementationSpecific() { } { T data[3*6]{}; ImageView<2, T> a{PixelStorage{}.setAlignment(1), - GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, data}; + GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, data, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(a.formatExtra(), UnsignedInt(GL::PixelType::UnsignedShort)); CORRADE_COMPARE(a.pixelSize(), 6); @@ -281,8 +293,9 @@ template void ImageViewTest::constructImplementationSpecific() { /* Manual pixel size */ { T data[3*6]{}; - ImageView<2, T> a{PixelStorage{}.setAlignment(1), 666, 1337, 6, {1, 3}, data}; + ImageView<2, T> a{PixelStorage{}.setAlignment(1), 666, 1337, 6, {1, 3}, data, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(a.formatExtra(), UnsignedInt(GL::PixelType::UnsignedShort)); @@ -298,8 +311,9 @@ template void ImageViewTest::constructImplementationSpecificEmpty() { /* Single format */ { - ImageView<2, T> a{Vk::PixelFormat::R32G32B32F, {2, 16}}; + ImageView<2, T> a{Vk::PixelFormat::R32G32B32F, {2, 16}, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().alignment(), 4); CORRADE_COMPARE(a.format(), pixelFormatWrap(Vk::PixelFormat::R32G32B32F)); CORRADE_COMPARE(a.formatExtra(), 0); @@ -308,8 +322,9 @@ template void ImageViewTest::constructImplementationSpecificEmpty() { CORRADE_COMPARE(a.data(), static_cast(nullptr)); } { ImageView<2, T> a{PixelStorage{}.setAlignment(1), - Vk::PixelFormat::R32G32B32F, {1, 2}}; + Vk::PixelFormat::R32G32B32F, {1, 2}, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), pixelFormatWrap(Vk::PixelFormat::R32G32B32F)); CORRADE_COMPARE(a.formatExtra(), 0); @@ -320,8 +335,9 @@ template void ImageViewTest::constructImplementationSpecificEmpty() { /* Format + extra */ { - ImageView<2, T> a{GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}}; + ImageView<2, T> a{GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().alignment(), 4); CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(a.formatExtra(), UnsignedInt(GL::PixelType::UnsignedShort)); @@ -330,8 +346,9 @@ template void ImageViewTest::constructImplementationSpecificEmpty() { CORRADE_COMPARE(a.data(), static_cast(nullptr)); } { ImageView<2, T> a{PixelStorage{}.setAlignment(1), - GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {8, 2}}; + GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {8, 2}, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(a.formatExtra(), UnsignedInt(GL::PixelType::UnsignedShort)); CORRADE_COMPARE(a.pixelSize(), 6); @@ -341,8 +358,9 @@ template void ImageViewTest::constructImplementationSpecificEmpty() { /* Manual pixel size */ { - ImageView<2, T> a{PixelStorage{}.setAlignment(1), 666, 1337, 6, {3, 3}}; + ImageView<2, T> a{PixelStorage{}.setAlignment(1), 666, 1337, 6, {3, 3}, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(a.formatExtra(), UnsignedInt(GL::PixelType::UnsignedShort)); @@ -357,8 +375,9 @@ template void ImageViewTest::constructCompressedGeneric() { { T data[8]{}; - CompressedImageView<2, T> a{CompressedPixelFormat::Bc1RGBAUnorm, {4, 4}, data}; + CompressedImageView<2, T> a{CompressedPixelFormat::Bc1RGBAUnorm, {4, 4}, data, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{0}); CORRADE_COMPARE(a.format(), CompressedPixelFormat::Bc1RGBAUnorm); CORRADE_COMPARE(a.size(), (Vector2i{4, 4})); @@ -368,8 +387,9 @@ template void ImageViewTest::constructCompressedGeneric() { T data[8]{}; CompressedImageView<2, T> a{CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), CompressedPixelFormat::Bc1RGBAUnorm, {4, 4}, - data}; + data, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(a.format(), CompressedPixelFormat::Bc1RGBAUnorm); CORRADE_COMPARE(a.size(), (Vector2i{4, 4})); @@ -382,16 +402,18 @@ template void ImageViewTest::constructCompressedGenericEmpty() { setTestCaseTemplateName(MutabilityTraits::name()); { - CompressedImageView<2, T> a{CompressedPixelFormat::Bc1RGBAUnorm, {8, 16}}; + CompressedImageView<2, T> a{CompressedPixelFormat::Bc1RGBAUnorm, {8, 16}, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{0}); CORRADE_COMPARE(a.format(), CompressedPixelFormat::Bc1RGBAUnorm); CORRADE_COMPARE(a.size(), (Vector2i{8, 16})); CORRADE_COMPARE(a.data(), static_cast(nullptr)); } { CompressedImageView<2, T> a{CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), - CompressedPixelFormat::Bc1RGBAUnorm, {8, 16}}; + CompressedPixelFormat::Bc1RGBAUnorm, {8, 16}, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(a.format(), CompressedPixelFormat::Bc1RGBAUnorm); CORRADE_COMPARE(a.size(), (Vector2i{8, 16})); @@ -406,8 +428,9 @@ template void ImageViewTest::constructCompressedImplementationSpecific( { T data[8]{}; CompressedImageView<2, T> a{GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 4}, - data}; + data, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{0}); CORRADE_COMPARE(a.format(), compressedPixelFormatWrap(GL::CompressedPixelFormat::RGBS3tcDxt1)); CORRADE_COMPARE(a.size(), (Vector2i{4, 4})); @@ -416,8 +439,9 @@ template void ImageViewTest::constructCompressedImplementationSpecific( } { T data[8]{}; CompressedImageView<2, T> a{CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), - GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 4}, data}; + GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 4}, data, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(a.format(), compressedPixelFormatWrap(GL::CompressedPixelFormat::RGBS3tcDxt1)); CORRADE_COMPARE(a.size(), (Vector2i{4, 4})); @@ -433,16 +457,18 @@ template void ImageViewTest::constructCompressedImplementationSpecificE /* Format with autodetection */ { - CompressedImageView<2, T> a{GL::CompressedPixelFormat::RGBS3tcDxt1, {8, 16}}; + CompressedImageView<2, T> a{GL::CompressedPixelFormat::RGBS3tcDxt1, {8, 16}, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{0}); CORRADE_COMPARE(a.format(), compressedPixelFormatWrap(GL::CompressedPixelFormat::RGBS3tcDxt1)); CORRADE_COMPARE(a.size(), (Vector2i{8, 16})); CORRADE_COMPARE(a.data(), static_cast(nullptr)); } { CompressedImageView<2, T> a{CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), - GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 8}}; + GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 8}, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(a.format(), compressedPixelFormatWrap(GL::CompressedPixelFormat::RGBS3tcDxt1)); CORRADE_COMPARE(a.size(), (Vector2i{4, 8})); @@ -456,7 +482,9 @@ void ImageViewTest::construct3DFrom1D() { /* Copy of "Manual pixel size" in constructImplementationSpecific(), as that exposes most fields */ const char data[3*6]{}; - ImageView1D a{PixelStorage{}.setAlignment(1), 666, 1337, 6, 3, data}; + /** @todo use a real flag once it exists */ + ImageView1D a{PixelStorage{}.setAlignment(1), 666, 1337, 6, 3, data, ImageFlag1D(0xdea0)}; + CORRADE_COMPARE(a.flags(), ImageFlag1D(0xdea0)); CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(a.formatExtra(), UnsignedInt(GL::PixelType::UnsignedShort)); @@ -465,7 +493,10 @@ void ImageViewTest::construct3DFrom1D() { CORRADE_COMPARE(a.data(), &data[0]); CORRADE_COMPARE(a.data().size(), 3*6); - ImageView3D b = a; /* implicit conversion allowed */ + /* Not testing the flags parameter here to be sure implicit conversion + works as well, it's tested in construct3DFrom2D() below */ + ImageView3D b = a; + CORRADE_COMPARE(b.flags(), ImageFlag3D(0xdea0)); CORRADE_COMPARE(b.storage().alignment(), 1); CORRADE_COMPARE(b.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(b.formatExtra(), UnsignedInt(GL::PixelType::UnsignedShort)); @@ -486,7 +517,8 @@ void ImageViewTest::construct3DFrom2D() { /* Copy of "Manual pixel size" in constructImplementationSpecific(), as that exposes most fields */ char data[3*6]{}; - MutableImageView2D a{PixelStorage{}.setAlignment(1), 666, 1337, 6, {1, 3}, data}; + MutableImageView2D a{PixelStorage{}.setAlignment(1), 666, 1337, 6, {1, 3}, data, ImageFlag2D::Array|ImageFlag2D(0xde00)}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array|ImageFlag2D(0xde00)); CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(a.formatExtra(), UnsignedInt(GL::PixelType::UnsignedShort)); @@ -495,7 +527,10 @@ void ImageViewTest::construct3DFrom2D() { CORRADE_COMPARE(a.data(), &data[0]); CORRADE_COMPARE(a.data().size(), 3*6); - MutableImageView3D b = a; + MutableImageView3D b = {a, ImageFlag3D(0x00a0)}; + /* The Array flag got implicitly stripped away, the rest got passed through + and combined with the flags argument */ + CORRADE_COMPARE(b.flags(), ImageFlag3D(0xdea0)); CORRADE_COMPARE(b.storage().alignment(), 1); CORRADE_COMPARE(b.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(b.formatExtra(), UnsignedInt(GL::PixelType::UnsignedShort)); @@ -516,15 +551,20 @@ void ImageViewTest::constructCompressed3DFrom1D() { /** @todo S3TC doesn't have 1D compression so this might blow up once we check for block sizes */ const char data[8]{}; + /** @todo use a real flag once it exists */ CompressedImageView1D a{CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), - GL::CompressedPixelFormat::RGBS3tcDxt1, 4, data}; + GL::CompressedPixelFormat::RGBS3tcDxt1, 4, data, ImageFlag1D(0xdea0)}; + CORRADE_COMPARE(a.flags(), ImageFlag1D(0xdea0)); CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(a.format(), compressedPixelFormatWrap(GL::CompressedPixelFormat::RGBS3tcDxt1)); CORRADE_COMPARE(a.size(), 4); CORRADE_COMPARE(a.data(), &data[0]); CORRADE_COMPARE(a.data().size(), 8); + /* Not testing the flags parameter here to be sure implicit conversion + works as well, it's tested in constructCompressed3DFrom2D() below */ CompressedImageView3D b = a; + CORRADE_COMPARE(b.flags(), ImageFlag3D(0xdea0)); CORRADE_COMPARE(b.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(b.format(), compressedPixelFormatWrap(GL::CompressedPixelFormat::RGBS3tcDxt1)); CORRADE_COMPARE(b.size(), (Vector3i{4, 1, 1})); @@ -544,14 +584,18 @@ void ImageViewTest::constructCompressed3DFrom2D() { most fields */ char data[8*2]{}; MutableCompressedImageView2D a{CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), - GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 8}, data}; + GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 8}, data, ImageFlag2D::Array|ImageFlag2D(0xde00)}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array|ImageFlag2D(0xde00)); CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(a.format(), compressedPixelFormatWrap(GL::CompressedPixelFormat::RGBS3tcDxt1)); CORRADE_COMPARE(a.size(), (Vector2i{4, 8})); CORRADE_COMPARE(a.data(), &data[0]); CORRADE_COMPARE(a.data().size(), 8*2); - MutableCompressedImageView3D b = a; + MutableCompressedImageView3D b = {a, ImageFlag3D(0x00a0)}; + /* The Array flag got implicitly stripped away, the rest got passed through + and combined with the flags argument */ + CORRADE_COMPARE(b.flags(), ImageFlag3D(0xdea0)); CORRADE_COMPARE(b.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(b.format(), compressedPixelFormatWrap(GL::CompressedPixelFormat::RGBS3tcDxt1)); CORRADE_COMPARE(b.size(), (Vector3i{4, 8, 1})); @@ -568,7 +612,8 @@ void ImageViewTest::constructFromMutable() { /* Copy of "Manual pixel size" in constructImplementationSpecific(), as that exposes most fields */ char data[3*6]{}; - MutableImageView2D a{PixelStorage{}.setAlignment(1), 666, 1337, 6, {1, 3}, data}; + MutableImageView2D a{PixelStorage{}.setAlignment(1), 666, 1337, 6, {1, 3}, data, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(a.formatExtra(), UnsignedInt(GL::PixelType::UnsignedShort)); @@ -578,6 +623,7 @@ void ImageViewTest::constructFromMutable() { CORRADE_COMPARE(a.data().size(), 3*6); ImageView2D b = a; + CORRADE_COMPARE(b.flags(), ImageFlag2D::Array); CORRADE_COMPARE(b.storage().alignment(), 1); CORRADE_COMPARE(b.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(b.formatExtra(), UnsignedInt(GL::PixelType::UnsignedShort)); @@ -592,7 +638,8 @@ void ImageViewTest::constructCompressedFromMutable() { most fields */ char data[8]{}; MutableCompressedImageView2D a{CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), - GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 4}, data}; + GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 4}, data, ImageFlag2D::Array}; + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(a.format(), compressedPixelFormatWrap(GL::CompressedPixelFormat::RGBS3tcDxt1)); CORRADE_COMPARE(a.size(), (Vector2i{4, 4})); @@ -600,6 +647,7 @@ void ImageViewTest::constructCompressedFromMutable() { CORRADE_COMPARE(a.data().size(), 8); CompressedImageView2D b = a; + CORRADE_COMPARE(b.flags(), ImageFlag2D::Array); CORRADE_COMPARE(b.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(b.format(), compressedPixelFormatWrap(GL::CompressedPixelFormat::RGBS3tcDxt1)); CORRADE_COMPARE(b.size(), (Vector2i{4, 4})); @@ -610,16 +658,14 @@ void ImageViewTest::constructCompressedFromMutable() { void ImageViewTest::constructNullptr() { #ifdef MAGNUM_BUILD_DEPRECATED CORRADE_SKIP("This is still allowed on a deprecated build, can't test."); - #endif - - #ifdef CORRADE_NO_ASSERT + #elif defined(CORRADE_NO_ASSERT) CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); - #endif - + #else std::ostringstream out; Error redirectError{&out}; ImageView2D{PixelFormat::RGB8Unorm, {1, 3}, nullptr}; CORRADE_COMPARE(out.str(), "ImageView: data too small, got 0 but expected at least 12 bytes\n"); + #endif } void ImageViewTest::constructInvalidSize() { @@ -636,6 +682,29 @@ void ImageViewTest::constructInvalidSize() { CORRADE_COMPARE(out.str(), "ImageView: data too small, got 9 but expected at least 12 bytes\n"); } +void ImageViewTest::constructInvalidCubeMap() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + const char data[4*3*18*4]{}; + + std::ostringstream out; + Error redirectError{&out}; + ImageView3D{PixelFormat::RGBA8Unorm, {3, 3, 5}, data, ImageFlag3D::CubeMap}; + ImageView3D{PixelFormat::RGBA8Unorm, {3, 4, 6}, data, ImageFlag3D::CubeMap}; + ImageView3D{PixelFormat::RGBA8Unorm, {3, 3, 17}, data, ImageFlag3D::CubeMap |ImageFlag3D::Array}; + ImageView3D{PixelFormat::RGBA8Unorm, {4, 3, 18}, data, ImageFlag3D::CubeMap |ImageFlag3D::Array}; + /* The data-less variant should call into the same assertion helper */ + ImageView3D{PixelFormat::RGBA8Unorm, {3, 3, 5}, ImageFlag3D::CubeMap}; + CORRADE_COMPARE(out.str(), + "ImageView: expected exactly 6 faces for a cube map, got 5\n" + "ImageView: expected square faces for a cube map, got {3, 4}\n" + "ImageView: expected a multiple of 6 faces for a cube map array, got 17\n" + "ImageView: expected square faces for a cube map, got {4, 3}\n" + "ImageView: expected exactly 6 faces for a cube map, got 5\n"); +} + void ImageViewTest::constructCompressedInvalidSize() { CORRADE_EXPECT_FAIL("Size checking for compressed image data is not implemented yet."); @@ -657,6 +726,29 @@ void ImageViewTest::constructCompressedInvalidSize() { } } +void ImageViewTest::constructCompressedInvalidCubeMap() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + const char data[8*18]{}; + + std::ostringstream out; + Error redirectError{&out}; + CompressedImageView3D{CompressedPixelFormat::Bc1RGBAUnorm, {3, 3, 5}, data, ImageFlag3D::CubeMap}; + CompressedImageView3D{CompressedPixelFormat::Bc1RGBAUnorm, {3, 4, 6}, data, ImageFlag3D::CubeMap}; + CompressedImageView3D{CompressedPixelFormat::Bc1RGBAUnorm, {3, 3, 17}, data, ImageFlag3D::CubeMap |ImageFlag3D::Array}; + CompressedImageView3D{CompressedPixelFormat::Bc1RGBAUnorm, {4, 3, 18}, data, ImageFlag3D::CubeMap |ImageFlag3D::Array}; + /* The data-less variant should call into the same assertion helper */ + CompressedImageView3D{CompressedPixelFormat::Bc1RGBAUnorm, {3, 3, 5}, ImageFlag3D::CubeMap}; + CORRADE_COMPARE(out.str(), + "CompressedImageView: expected exactly 6 faces for a cube map, got 5\n" + "CompressedImageView: expected square faces for a cube map, got {3, 4}\n" + "CompressedImageView: expected a multiple of 6 faces for a cube map array, got 17\n" + "CompressedImageView: expected square faces for a cube map, got {4, 3}\n" + "CompressedImageView: expected exactly 6 faces for a cube map, got 5\n"); +} + void ImageViewTest::dataProperties() { const char data[224]{}; ImageView3D image{ diff --git a/src/Magnum/Trade/ImageData.cpp b/src/Magnum/Trade/ImageData.cpp index c07a91c969..195710ba35 100644 --- a/src/Magnum/Trade/ImageData.cpp +++ b/src/Magnum/Trade/ImageData.cpp @@ -33,61 +33,68 @@ namespace Magnum { namespace Trade { -template ImageData::ImageData(const PixelStorage storage, const PixelFormat format, const VectorTypeFor& size, Containers::Array&& data, const void* const importerState) noexcept: ImageData{storage, format, {}, pixelFormatSize(format), size, std::move(data), importerState} {} +template ImageData::ImageData(const PixelStorage storage, const PixelFormat format, const VectorTypeFor& size, Containers::Array&& data, const ImageFlags flags, const void* const importerState) noexcept: ImageData{storage, format, {}, pixelFormatSize(format), size, std::move(data), flags, importerState} {} -template ImageData::ImageData(const PixelStorage storage, const PixelFormat format, const VectorTypeFor& size, const DataFlags dataFlags, const Containers::ArrayView data, const void* const importerState) noexcept: ImageData{storage, format, size, Containers::Array{const_cast(static_cast(data.data())), data.size(), Implementation::nonOwnedArrayDeleter}, importerState} { +template ImageData::ImageData(const PixelStorage storage, const PixelFormat format, const VectorTypeFor& size, const DataFlags dataFlags, const Containers::ArrayView data, const ImageFlags flags, const void* const importerState) noexcept: ImageData{storage, format, size, Containers::Array{const_cast(static_cast(data.data())), data.size(), Implementation::nonOwnedArrayDeleter}, flags, importerState} { CORRADE_ASSERT(!(dataFlags & DataFlag::Owned), "Trade::ImageData: can't construct a non-owned instance with" << dataFlags, ); _dataFlags = dataFlags; } -template ImageData::ImageData(const PixelFormat format, const VectorTypeFor& size, Containers::Array&& data, const void* const importerState) noexcept: ImageData{{}, format, size, std::move(data), importerState} {} +template ImageData::ImageData(const PixelFormat format, const VectorTypeFor& size, Containers::Array&& data, const ImageFlags flags, const void* const importerState) noexcept: ImageData{{}, format, size, std::move(data), flags, importerState} {} -template ImageData::ImageData(const PixelFormat format, const VectorTypeFor& size, const DataFlags dataFlags, const Containers::ArrayView data, const void* const importerState) noexcept: ImageData{format, size, Containers::Array{const_cast(static_cast(data.data())), data.size(), Implementation::nonOwnedArrayDeleter}, importerState} { +template ImageData::ImageData(const PixelFormat format, const VectorTypeFor& size, const DataFlags dataFlags, const Containers::ArrayView data, const ImageFlags flags, const void* const importerState) noexcept: ImageData{format, size, Containers::Array{const_cast(static_cast(data.data())), data.size(), Implementation::nonOwnedArrayDeleter}, flags, importerState} { CORRADE_ASSERT(!(dataFlags & DataFlag::Owned), "Trade::ImageData: can't construct a non-owned instance with" << dataFlags, ); _dataFlags = dataFlags; } -template ImageData::ImageData(const PixelStorage storage, const UnsignedInt format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size, Containers::Array&& data, const void* const importerState) noexcept: ImageData{storage, pixelFormatWrap(format), formatExtra, pixelSize, size, std::move(data), importerState} {} +template ImageData::ImageData(const PixelStorage storage, const UnsignedInt format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size, Containers::Array&& data, const ImageFlags flags, const void* const importerState) noexcept: ImageData{storage, pixelFormatWrap(format), formatExtra, pixelSize, size, std::move(data), flags, importerState} {} -template ImageData::ImageData(const PixelStorage storage, const PixelFormat format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size, Containers::Array&& data, const void* const importerState) noexcept: _dataFlags{DataFlag::Owned|DataFlag::Mutable}, _compressed{false}, _storage{storage}, _format{format}, _formatExtra{formatExtra}, _pixelSize{pixelSize}, _size{size}, _data{std::move(data)}, _importerState{importerState} { +template ImageData::ImageData(const PixelStorage storage, const PixelFormat format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size, Containers::Array&& data, const ImageFlags flags, const void* const importerState) noexcept: _dataFlags{DataFlag::Owned|DataFlag::Mutable}, _compressed{false}, _flags{flags}, _storage{storage}, _format{format}, _formatExtra{formatExtra}, _pixelSize{pixelSize}, _size{size}, _data{std::move(data)}, _importerState{importerState} { CORRADE_ASSERT(Magnum::Implementation::imageDataSize(*this) <= _data.size(), "Trade::ImageData: data too small, got" << _data.size() << "but expected at least" << Magnum::Implementation::imageDataSize(*this) << "bytes", ); + #ifndef CORRADE_NO_ASSERT + Magnum::Implementation::checkImageFlagsForSize("Trade::ImageData:", flags, size); + #endif } -template ImageData::ImageData(const PixelStorage storage, const UnsignedInt format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size, const DataFlags dataFlags, const Containers::ArrayView data, const void* const importerState) noexcept: ImageData{storage, pixelFormatWrap(format), formatExtra, pixelSize, size, dataFlags, data, importerState} {} +template ImageData::ImageData(const PixelStorage storage, const UnsignedInt format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size, const DataFlags dataFlags, const Containers::ArrayView data, const ImageFlags flags, const void* const importerState) noexcept: ImageData{storage, pixelFormatWrap(format), formatExtra, pixelSize, size, dataFlags, data, flags, importerState} {} -template ImageData::ImageData(const PixelStorage storage, const PixelFormat format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size, const DataFlags dataFlags, Containers::ArrayView data, const void* const importerState) noexcept: ImageData{storage, format, formatExtra, pixelSize, size, Containers::Array{const_cast(static_cast(data.data())), data.size(), Implementation::nonOwnedArrayDeleter}, importerState} { +template ImageData::ImageData(const PixelStorage storage, const PixelFormat format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size, const DataFlags dataFlags, Containers::ArrayView data, const ImageFlags flags, const void* const importerState) noexcept: ImageData{storage, format, formatExtra, pixelSize, size, Containers::Array{const_cast(static_cast(data.data())), data.size(), Implementation::nonOwnedArrayDeleter}, flags, importerState} { CORRADE_ASSERT(!(dataFlags & DataFlag::Owned), "Trade::ImageData: can't construct a non-owned instance with" << dataFlags, ); _dataFlags = dataFlags; } -template ImageData::ImageData(const CompressedPixelStorage storage, const CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data, const void* const importerState) noexcept: _dataFlags{DataFlag::Owned|DataFlag::Mutable}, _compressed{true}, _compressedStorage{storage}, _compressedFormat{format}, _size{size}, _data{std::move(data)}, _importerState{importerState} {} +template ImageData::ImageData(const CompressedPixelStorage storage, const CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data, const ImageFlags flags, const void* const importerState) noexcept: _dataFlags{DataFlag::Owned|DataFlag::Mutable}, _compressed{true}, _flags{flags}, _compressedStorage{storage}, _compressedFormat{format}, _size{size}, _data{std::move(data)}, _importerState{importerState} { + #ifndef CORRADE_NO_ASSERT + Magnum::Implementation::checkImageFlagsForSize("Trade::ImageData:", flags, size); + #endif +} -template ImageData::ImageData(const CompressedPixelStorage storage, const CompressedPixelFormat format, const VectorTypeFor& size, const DataFlags dataFlags, const Containers::ArrayView data, const void* const importerState) noexcept: ImageData{storage, format, size, Containers::Array{const_cast(static_cast(data.data())), data.size(), Implementation::nonOwnedArrayDeleter}, importerState} { +template ImageData::ImageData(const CompressedPixelStorage storage, const CompressedPixelFormat format, const VectorTypeFor& size, const DataFlags dataFlags, const Containers::ArrayView data, const ImageFlags flags, const void* const importerState) noexcept: ImageData{storage, format, size, Containers::Array{const_cast(static_cast(data.data())), data.size(), Implementation::nonOwnedArrayDeleter}, flags, importerState} { CORRADE_ASSERT(!(dataFlags & DataFlag::Owned), "Trade::ImageData: can't construct a non-owned instance with" << dataFlags, ); _dataFlags = dataFlags; } -template ImageData::ImageData(const CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data, const void* const importerState) noexcept: ImageData{{}, format, size, std::move(data), importerState} {} +template ImageData::ImageData(const CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data, const ImageFlags flags, const void* const importerState) noexcept: ImageData{{}, format, size, std::move(data), flags, importerState} {} -template ImageData::ImageData(const CompressedPixelFormat format, const VectorTypeFor& size, const DataFlags dataFlags, const Containers::ArrayView data, const void* const importerState) noexcept: ImageData{format, size, Containers::Array{const_cast(static_cast(data.data())), data.size(), Implementation::nonOwnedArrayDeleter}, importerState} { +template ImageData::ImageData(const CompressedPixelFormat format, const VectorTypeFor& size, const DataFlags dataFlags, const Containers::ArrayView data, const ImageFlags flags, const void* const importerState) noexcept: ImageData{format, size, Containers::Array{const_cast(static_cast(data.data())), data.size(), Implementation::nonOwnedArrayDeleter}, flags, importerState} { CORRADE_ASSERT(!(dataFlags & DataFlag::Owned), "Trade::ImageData: can't construct a non-owned instance with" << dataFlags, ); _dataFlags = dataFlags; } -template ImageData::ImageData(const CompressedPixelStorage storage, const UnsignedInt format, const VectorTypeFor& size, Containers::Array&& data, const void* const importerState) noexcept: ImageData{storage, compressedPixelFormatWrap(format), size, std::move(data), importerState} {} +template ImageData::ImageData(const CompressedPixelStorage storage, const UnsignedInt format, const VectorTypeFor& size, Containers::Array&& data, const ImageFlags flags, const void* const importerState) noexcept: ImageData{storage, compressedPixelFormatWrap(format), size, std::move(data), flags, importerState} {} -template ImageData::ImageData(const CompressedPixelStorage storage, const UnsignedInt format, const VectorTypeFor& size, const DataFlags dataFlags, const Containers::ArrayView data, const void* const importerState) noexcept: ImageData{storage, format, size, Containers::Array{const_cast(static_cast(data.data())), data.size(), Implementation::nonOwnedArrayDeleter}, importerState} { +template ImageData::ImageData(const CompressedPixelStorage storage, const UnsignedInt format, const VectorTypeFor& size, const DataFlags dataFlags, const Containers::ArrayView data, const ImageFlags flags, const void* const importerState) noexcept: ImageData{storage, format, size, Containers::Array{const_cast(static_cast(data.data())), data.size(), Implementation::nonOwnedArrayDeleter}, flags, importerState} { CORRADE_ASSERT(!(dataFlags & DataFlag::Owned), "Trade::ImageData: can't construct a non-owned instance with" << dataFlags, ); _dataFlags = dataFlags; } -template ImageData::ImageData(ImageData&& other) noexcept: _dataFlags{other._dataFlags}, _compressed{std::move(other._compressed)}, _size{std::move(other._size)}, _data{std::move(other._data)}, _importerState{std::move(other._importerState)} { +template ImageData::ImageData(ImageData&& other) noexcept: _dataFlags{other._dataFlags}, _compressed{std::move(other._compressed)}, _flags{std::move(other._flags)}, _size{std::move(other._size)}, _data{std::move(other._data)}, _importerState{std::move(other._importerState)} { if(_compressed) { new(&_compressedStorage) CompressedPixelStorage{std::move(other._compressedStorage)}; _compressedFormat = std::move(other._compressedFormat); @@ -110,6 +117,7 @@ template ImageData& ImageData::o using std::swap; swap(_dataFlags, other._dataFlags); swap(_compressed, other._compressed); + swap(_flags, other._flags); if(_compressed) { swap(_compressedStorage, other._compressedStorage); swap(_compressedFormat, other._compressedFormat); @@ -181,21 +189,21 @@ template Containers::StridedArrayView ImageData::operator BasicImageView() const { CORRADE_ASSERT(!_compressed, "Trade::ImageData: the image is compressed", (BasicImageView{_storage, _format, _formatExtra, _pixelSize, _size})); - return BasicImageView{_storage, _format, _formatExtra, _pixelSize, _size, _data}; + return BasicImageView{_storage, _format, _formatExtra, _pixelSize, _size, _data, _flags}; } template ImageData::operator BasicMutableImageView() { CORRADE_ASSERT(_dataFlags & DataFlag::Mutable, "Trade::ImageData: the image is not mutable", (BasicMutableImageView{_storage, _format, _formatExtra, _pixelSize, _size})); CORRADE_ASSERT(!_compressed, "Trade::ImageData: the image is compressed", (BasicMutableImageView{_storage, _format, _formatExtra, _pixelSize, _size})); - return BasicMutableImageView{_storage, _format, _formatExtra, _pixelSize, _size, _data}; + return BasicMutableImageView{_storage, _format, _formatExtra, _pixelSize, _size, _data, _flags}; } template ImageData::operator BasicCompressedImageView() const { CORRADE_ASSERT(_compressed, "Trade::ImageData: the image is not compressed", (BasicCompressedImageView{_compressedStorage, _compressedFormat, _size})); return BasicCompressedImageView{ _compressedStorage, - _compressedFormat, _size, _data}; + _compressedFormat, _size, _data, _flags}; } template ImageData::operator BasicMutableCompressedImageView() { @@ -205,7 +213,7 @@ template ImageData::operator BasicMutableCom CORRADE_ASSERT(_compressed, "Trade::ImageData: the image is not compressed", (BasicMutableCompressedImageView{_compressedStorage, _compressedFormat, _size})); return BasicMutableCompressedImageView{ _compressedStorage, - _compressedFormat, _size, _data}; + _compressedFormat, _size, _data, _flags}; } template Containers::Array ImageData::release() { diff --git a/src/Magnum/Trade/ImageData.h b/src/Magnum/Trade/ImageData.h index 71ac0a8d96..2455028c68 100644 --- a/src/Magnum/Trade/ImageData.h +++ b/src/Magnum/Trade/ImageData.h @@ -32,6 +32,7 @@ #include #include "Magnum/DimensionTraits.h" +#include "Magnum/ImageFlags.h" #include "Magnum/PixelStorage.h" #include "Magnum/Trade/Data.h" #include "Magnum/Trade/Trade.h" @@ -115,17 +116,30 @@ template class ImageData { * @param format Format of pixel data * @param size Image size * @param data Image data + * @param flags Image layout flags * @param importerState Importer-specific state + * @m_since_latest * * The @p data array is expected to be of proper size for given - * parameters. + * parameters. For a 3D image, if @p flags contain + * @ref ImageFlag3D::CubeMap, the @p size is expected to match its + * restrictions. * * The @ref dataFlags() are implicitly set to a combination of * @ref DataFlag::Owned and @ref DataFlag::Mutable. For non-owned data - * use the @ref ImageData(PixelStorage, PixelFormat, const VectorTypeFor&, DataFlags, Containers::ArrayView, const void*) + * use the @ref ImageData(PixelStorage, PixelFormat, const VectorTypeFor&, DataFlags, Containers::ArrayView, ImageFlags, const void*) * constructor instead. */ - explicit ImageData(PixelStorage storage, PixelFormat format, const VectorTypeFor& size, Containers::Array&& data, const void* importerState = nullptr) noexcept; + explicit ImageData(PixelStorage storage, PixelFormat format, const VectorTypeFor& size, Containers::Array&& data, ImageFlags flags = {}, const void* importerState = nullptr) noexcept; + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @brief @copybrief ImageData(PixelStorage, PixelFormat, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) + * @m_deprecated_since_latest Use @ref ImageData(PixelStorage, PixelFormat, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) + * instead. + */ + explicit CORRADE_DEPRECATED("use a constructor with an extra ImageFlags argument instead") ImageData(PixelStorage storage, PixelFormat format, const VectorTypeFor& size, Containers::Array&& data, const void* importerState) noexcept: ImageData{storage, format, size, std::move(data), {}, importerState} {} + #endif /** * @brief Construct a non-owned uncompressed image data @@ -134,28 +148,49 @@ template class ImageData { * @param size Image size * @param dataFlags Data flags * @param data View on image data + * @param flags Image layout flags * @param importerState Importer-specific state - * @m_since{2020,06} + * @m_since_latest * - * Compared to @ref ImageData(PixelStorage, PixelFormat, const VectorTypeFor&, Containers::Array&&, const void*) + * Compared to @ref ImageData(PixelStorage, PixelFormat, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) * creates an instance that doesn't own the passed data. The * @p dataFlags parameter can contain @ref DataFlag::Mutable to * indicate the external data can be modified, and is expected to *not* * have @ref DataFlag::Owned set. */ - explicit ImageData(PixelStorage storage, PixelFormat format, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, const void* importerState = nullptr) noexcept; + explicit ImageData(PixelStorage storage, PixelFormat format, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, ImageFlags flags = {}, const void* importerState = nullptr) noexcept; + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @brief @copybrief ImageData(PixelStorage, PixelFormat, const VectorTypeFor&, DataFlags, Containers::ArrayView, ImageFlags, const void*) + * @m_deprecated_since_latest Use @ref ImageData(PixelStorage, PixelFormat, const VectorTypeFor&, DataFlags, Containers::ArrayView, ImageFlags, const void*) + * instead. + */ + explicit CORRADE_DEPRECATED("use a constructor with an extra ImageFlags argument instead") ImageData(PixelStorage storage, PixelFormat format, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, const void* importerState) noexcept: ImageData{storage, format, size, dataFlags, data, {}, importerState} {} + #endif /** * @brief Construct an uncompressed image data * @param format Format of pixel data * @param size Image size * @param data Image data + * @param flags Image layout flags * @param importerState Importer-specific state + * @m_since_latest * - * Equivalent to calling @ref ImageData(PixelStorage, PixelFormat, const VectorTypeFor&, Containers::Array&&, const void*) + * Equivalent to calling @ref ImageData(PixelStorage, PixelFormat, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) * with default-constructed @ref PixelStorage. */ - explicit ImageData(PixelFormat format, const VectorTypeFor& size, Containers::Array&& data, const void* importerState = nullptr) noexcept; + explicit ImageData(PixelFormat format, const VectorTypeFor& size, Containers::Array&& data, ImageFlags flags = {}, const void* importerState = nullptr) noexcept; + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @brief @copybrief ImageData(PixelFormat, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) + * @m_deprecated_since_latest Use @ref ImageData(PixelFormat, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) + * instead. + */ + explicit CORRADE_DEPRECATED("use a constructor with an extra ImageFlags argument instead") ImageData(PixelFormat format, const VectorTypeFor& size, Containers::Array&& data, const void* importerState) noexcept: ImageData{format, size, std::move(data), {}, importerState} {} + #endif /** * @brief Construct a non-owned uncompressed image data @@ -163,16 +198,26 @@ template class ImageData { * @param size Image size * @param dataFlags Data flags * @param data View on image data + * @param flags Image layout flags * @param importerState Importer-specific state - * @m_since{2020,06} + * @m_since_latest * - * Compared to @ref ImageData(PixelFormat, const VectorTypeFor&, Containers::Array&&, const void*) + * Compared to @ref ImageData(PixelFormat, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) * creates an instance that doesn't own the passed data. The * @p dataFlags parameter can contain @ref DataFlag::Mutable to * indicate the external data can be modified, and is expected to *not* * have @ref DataFlag::Owned set. */ - explicit ImageData(PixelFormat format, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, const void* importerState = nullptr) noexcept; + explicit ImageData(PixelFormat format, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, ImageFlags flags = {}, const void* importerState = nullptr) noexcept; + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @brief @copybrief ImageData(PixelFormat, const VectorTypeFor&, DataFlags, Containers::ArrayView, ImageFlags, const void*) + * @m_deprecated_since_latest Use @ref ImageData(PixelFormat, const VectorTypeFor&, DataFlags, Containers::ArrayView, ImageFlags, const void*) + * instead. + */ + explicit CORRADE_DEPRECATED("use a constructor with an extra ImageFlags argument instead") ImageData(PixelFormat format, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, const void* importerState) noexcept: ImageData{format, size, dataFlags, data, {}, importerState} {} + #endif /** * @brief Construct an uncompressed image data with implementation-specific pixel format @@ -182,9 +227,11 @@ template class ImageData { * @param pixelSize Size of a pixel in given format, in bytes * @param size Image size, in pixels * @param data Image data + * @param flags Image layout flags * @param importerState Importer-specific state + * @m_since_latest * - * Unlike with @ref ImageData(PixelStorage, PixelFormat, const VectorTypeFor&, Containers::Array&&, const void*), + * Unlike with @ref ImageData(PixelStorage, PixelFormat, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*), * where pixel size is calculated automatically using * @ref pixelFormatSize(), this allows you to specify an * implementation-specific pixel format and pixel size directly. Uses @@ -192,19 +239,38 @@ template class ImageData { * @ref Magnum::PixelFormat "PixelFormat". * * The @p data array is expected to be of proper size for given - * parameters. The @ref dataFlags() are implicitly set to a combination - * of @ref DataFlag::Owned and @ref DataFlag::Mutable. For non-owned - * data use the @ref ImageData(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, DataFlags, Containers::ArrayView, const void*) + * parameters. For a 3D image, if @p flags contain + * @ref ImageFlag3D::CubeMap, the @p size is expected to match its + * restrictions. The @ref dataFlags() are implicitly set to a + * combination of @ref DataFlag::Owned and @ref DataFlag::Mutable. For + * non-owned data use the @ref ImageData(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, DataFlags, Containers::ArrayView, ImageFlags, const void*) * constructor instead. */ - explicit ImageData(PixelStorage storage, UnsignedInt format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, Containers::Array&& data, const void* importerState = nullptr) noexcept; + explicit ImageData(PixelStorage storage, UnsignedInt format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, Containers::Array&& data, ImageFlags flags = {}, const void* importerState = nullptr) noexcept; /** @overload + * @m_since_latest * * Equivalent to the above for @p format already wrapped with * @ref pixelFormatWrap(). */ - explicit ImageData(PixelStorage storage, PixelFormat format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, Containers::Array&& data, const void* importerState = nullptr) noexcept; + explicit ImageData(PixelStorage storage, PixelFormat format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, Containers::Array&& data, ImageFlags flags = {}, const void* importerState = nullptr) noexcept; + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @brief @copybrief ImageData(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) + * @m_deprecated_since_latest Use @ref ImageData(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) + * instead. + */ + explicit CORRADE_DEPRECATED("use a constructor with an extra ImageFlags argument instead") ImageData(PixelStorage storage, UnsignedInt format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, Containers::Array&& data, const void* importerState) noexcept: ImageData{storage, format, formatExtra, pixelSize, size, std::move(data), {}, importerState} {} + + /** + * @overload + * @m_deprecated_since_latest Use @ref ImageData(PixelStorage, PixelFormat, UnsignedInt, UnsignedInt, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) + * instead. + */ + explicit CORRADE_DEPRECATED("use a constructor with an extra ImageFlags argument instead") ImageData(PixelStorage storage, PixelFormat format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, Containers::Array&& data, const void* importerState) noexcept: ImageData{storage, format, formatExtra, pixelSize, size, std::move(data), {}, importerState} {} + #endif /** * @brief Construct a non-owned uncompressed image data with implementation-specific pixel format @@ -215,24 +281,41 @@ template class ImageData { * @param size Image size, in pixels * @param dataFlags Data flags * @param data View on image data + * @param flags Image layout flags * @param importerState Importer-specific state - * @m_since{2020,06} + * @m_since_latest * - * Compared to @ref ImageData(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, Containers::Array&&, const void*) + * Compared to @ref ImageData(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) * creates an instance that doesn't own the passed data. The * @p dataFlags parameter can contain @ref DataFlag::Mutable to * indicate the external data can be modified, and is expected to *not* * have @ref DataFlag::Owned set. */ - explicit ImageData(PixelStorage storage, UnsignedInt format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, const void* importerState = nullptr) noexcept; + explicit ImageData(PixelStorage storage, UnsignedInt format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, ImageFlags flags = {}, const void* importerState = nullptr) noexcept; /** @overload - * @m_since{2020,06} + * @m_since_latest * * Equivalent to the above for @p format already wrapped with * @ref pixelFormatWrap(). */ - explicit ImageData(PixelStorage storage, PixelFormat format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, const void* importerState = nullptr) noexcept; + explicit ImageData(PixelStorage storage, PixelFormat format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, ImageFlags flags = {}, const void* importerState = nullptr) noexcept; + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @brief @copybrief ImageData(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, DataFlags, Containers::ArrayView, ImageFlags, const void*) + * @m_deprecated_since_latest Use @ref ImageData(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, DataFlags, Containers::ArrayView, ImageFlags, const void*) + * instead. + */ + explicit CORRADE_DEPRECATED("use a constructor with an extra ImageFlags argument instead") ImageData(PixelStorage storage, UnsignedInt format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, const void* importerState) noexcept: ImageData{storage, format, formatExtra, pixelSize, size, dataFlags, data, {}, importerState} {} + + /** + * @overload + * @m_deprecated_since_latest Use @ref ImageData(PixelStorage, PixelFormat, UnsignedInt, UnsignedInt, const VectorTypeFor&, DataFlags, Containers::ArrayView, ImageFlags, const void*) + * instead. + */ + explicit CORRADE_DEPRECATED("use a constructor with an extra ImageFlags argument instead") ImageData(PixelStorage storage, PixelFormat format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, const void* importerState) noexcept: ImageData{storage, format, formatExtra, pixelSize, size, dataFlags, data, {}, importerState} {} + #endif /** * @brief Construct an uncompressed image data with implementation-specific pixel format @@ -241,13 +324,24 @@ template class ImageData { * @param formatExtra Additional pixel format specifier * @param size Image size * @param data Image data + * @param flags Image layout flags * @param importerState Importer-specific state + * @m_since_latest * * Uses ADL to find a corresponding @cpp pixelFormatSize(T, U) @ce - * overload, then calls @ref ImageData(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, Containers::Array&&, const void*) + * overload, then calls @ref ImageData(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) * with calculated pixel size. */ - template explicit ImageData(PixelStorage storage, T format, U formatExtra, const VectorTypeFor& size, Containers::Array&& data, const void* importerState = nullptr) noexcept; + template explicit ImageData(PixelStorage storage, T format, U formatExtra, const VectorTypeFor& size, Containers::Array&& data, ImageFlags flags = {}, const void* importerState = nullptr) noexcept; + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @brief @copybrief ImageData(PixelStorage, T, U, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) + * @m_deprecated_since_latest Use @ref ImageData(PixelStorage, T, U, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) + * instead. + */ + template explicit CORRADE_DEPRECATED("use a constructor with an extra ImageFlags argument instead") ImageData(PixelStorage storage, T format, U formatExtra, const VectorTypeFor& size, Containers::Array&& data, const void* importerState) noexcept: ImageData{storage, format, formatExtra, size, std::move(data), {}, importerState} {} + #endif /** * @brief Construct a non-owned uncompressed image data with implementation-specific pixel format @@ -257,16 +351,26 @@ template class ImageData { * @param size Image size * @param dataFlags Data flags * @param data View on image data + * @param flags Image layout flags * @param importerState Importer-specific state - * @m_since{2020,06} + * @m_since_latest * - * Compared to @ref ImageData(PixelStorage, T, U, const VectorTypeFor&, Containers::Array&&, const void*) + * Compared to @ref ImageData(PixelStorage, T, U, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) * creates an instance that doesn't own the passed data. The * @p dataFlags parameter can contain @ref DataFlag::Mutable to * indicate the external data can be modified, and is expected to *not* * have @ref DataFlag::Owned set. */ - template explicit ImageData(PixelStorage storage, T format, U formatExtra, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, const void* importerState = nullptr) noexcept; + template explicit ImageData(PixelStorage storage, T format, U formatExtra, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, ImageFlags flags = {}, const void* importerState = nullptr) noexcept; + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @brief @copybrief ImageData(PixelStorage, T, U, const VectorTypeFor&, DataFlags, Containers::ArrayView, ImageFlags, const void*) + * @m_deprecated_since_latest Use @ref ImageData(PixelStorage, T, U, const VectorTypeFor&, DataFlags, Containers::ArrayView, ImageFlags, const void*) + * instead. + */ + template explicit CORRADE_DEPRECATED("use a constructor with an extra ImageFlags argument instead") ImageData(PixelStorage storage, T format, U formatExtra, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, const void* importerState) noexcept: ImageData{storage, format, formatExtra, size, dataFlags, data, {}, importerState} {} + #endif /** * @brief Construct an uncompressed image data with implementation-specific pixel format @@ -274,13 +378,24 @@ template class ImageData { * @param format Format of pixel data * @param size Image size * @param data Image data + * @param flags Image layout flags * @param importerState Importer-specific state + * @m_since_latest * * Uses ADL to find a corresponding @cpp pixelFormatSize(T) @ce - * overload, then calls @ref ImageData(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, Containers::Array&&, const void*) + * overload, then calls @ref ImageData(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) * with calculated pixel size and @p formatExtra set to @cpp 0 @ce. */ - template explicit ImageData(PixelStorage storage, T format, const VectorTypeFor& size, Containers::Array&& data, const void* importerState = nullptr) noexcept; + template explicit ImageData(PixelStorage storage, T format, const VectorTypeFor& size, Containers::Array&& data, ImageFlags flags = {}, const void* importerState = nullptr) noexcept; + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @brief @copybrief ImageData(PixelStorage, T, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) + * @m_deprecated_since_latest Use @ref ImageData(PixelStorage, T, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) + * instead. + */ + template explicit CORRADE_DEPRECATED("use a constructor with an extra ImageFlags argument instead") ImageData(PixelStorage storage, T format, const VectorTypeFor& size, Containers::Array&& data, const void* importerState) noexcept: ImageData{storage, format, size, std::move(data), {}, importerState} {} + #endif /** * @brief Construct a non-owned uncompressed image data with implementation-specific pixel format @@ -289,16 +404,26 @@ template class ImageData { * @param size Image size * @param dataFlags Data flags * @param data view on image data + * @param flags Image layout flags * @param importerState Importer-specific state - * @m_since{2020,06} + * @m_since_latest * - * Compared to @ref ImageData(PixelStorage, T, const VectorTypeFor&, Containers::Array&&, const void*) + * Compared to @ref ImageData(PixelStorage, T, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) * creates an instance that doesn't own the passed data. The * @p dataFlags parameter can contain @ref DataFlag::Mutable to * indicate the external data can be modified, and is expected to *not* * have @ref DataFlag::Owned set. */ - template explicit ImageData(PixelStorage storage, T format, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, const void* importerState = nullptr) noexcept; + template explicit ImageData(PixelStorage storage, T format, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, ImageFlags flags = {}, const void* importerState = nullptr) noexcept; + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @brief @copybrief ImageData(PixelStorage, T, const VectorTypeFor&, DataFlags, Containers::ArrayView, ImageFlags, const void*) + * @m_deprecated_since_latest Use @ref ImageData(PixelStorage, T, const VectorTypeFor&, DataFlags, Containers::ArrayView, ImageFlags, const void*) + * instead. + */ + template explicit CORRADE_DEPRECATED("use a constructor with an extra ImageFlags argument instead") ImageData(PixelStorage storage, T format, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, const void* importerState) noexcept: ImageData{storage, format, size, dataFlags, data, {}, importerState} {} + #endif /** * @brief Construct a compressed image data @@ -306,9 +431,20 @@ template class ImageData { * @param format Format of compressed pixel data * @param size Image size * @param data Image data + * @param flags Image layout flags * @param importerState Importer-specific state + * @m_since_latest */ - explicit ImageData(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data, const void* importerState = nullptr) noexcept; + explicit ImageData(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data, ImageFlags flags = {}, const void* importerState = nullptr) noexcept; + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @brief @copybrief ImageData(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) + * @m_deprecated_since_latest Use @ref ImageData(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) + * instead. + */ + explicit CORRADE_DEPRECATED("use a constructor with an extra ImageFlags argument instead") ImageData(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data, const void* importerState) noexcept: ImageData{storage, format, size, std::move(data), {}, importerState} {} + #endif /** * @brief Construct a non-owned compressed image data @@ -317,28 +453,49 @@ template class ImageData { * @param size Image size * @param dataFlags Data flags * @param data View on image data + * @param flags Image layout flags * @param importerState Importer-specific state - * @m_since{2020,06} + * @m_since_latest * - * Compared to @ref ImageData(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, Containers::Array&&, const void*) + * Compared to @ref ImageData(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) * creates an instance that doesn't own the passed data. The * @p dataFlags parameter can contain @ref DataFlag::Mutable to * indicate the external data can be modified, and is expected to *not* * have @ref DataFlag::Owned set. */ - explicit ImageData(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, const void* importerState = nullptr) noexcept; + explicit ImageData(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, ImageFlags flags = {}, const void* importerState = nullptr) noexcept; + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @brief @copybrief ImageData(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, DataFlags, Containers::ArrayView, ImageFlags, const void*) + * @m_deprecated_since_latest Use @ref ImageData(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, DataFlags, Containers::ArrayView, ImageFlags, const void*) + * instead. + */ + explicit CORRADE_DEPRECATED("use a constructor with an extra ImageFlags argument instead") ImageData(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, const void* importerState) noexcept: ImageData{storage, format, size, dataFlags, data, {}, importerState} {} + #endif /** * @brief Construct a compressed image data * @param format Format of compressed pixel data * @param size Image size * @param data Image data + * @param flags Image layout flags * @param importerState Importer-specific state + * @m_since_latest * - * Equivalent to calling @ref ImageData(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, Containers::Array&&, const void*) + * Equivalent to calling @ref ImageData(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) * with default-constructed @ref CompressedPixelStorage. */ - explicit ImageData(CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data, const void* importerState = nullptr) noexcept; + explicit ImageData(CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data, ImageFlags flags = {}, const void* importerState = nullptr) noexcept; + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @brief @copybrief ImageData(CompressedPixelFormat, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) + * @m_deprecated_since_latest Use @ref ImageData(CompressedPixelFormat, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) + * instead. + */ + explicit CORRADE_DEPRECATED("use a constructor with an extra ImageFlags argument instead") ImageData(CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data, const void* importerState) noexcept: ImageData{format, size, std::move(data), {}, importerState} {} + #endif /** * @brief Construct a non-owned compressed image data @@ -346,16 +503,26 @@ template class ImageData { * @param size Image size * @param dataFlags Data flags * @param data View on image data + * @param flags Image layout flags * @param importerState Importer-specific state - * @m_since{2020,06} + * @m_since_latest * - * Compared to @ref ImageData(CompressedPixelFormat, const VectorTypeFor&, Containers::Array&&, const void*) + * Compared to @ref ImageData(CompressedPixelFormat, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) * creates an instance that doesn't own the passed data. The * @p dataFlags parameter can contain @ref DataFlag::Mutable to * indicate the external data can be modified, and is expected to *not* * have @ref DataFlag::Owned set. */ - explicit ImageData(CompressedPixelFormat format, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, const void* importerState = nullptr) noexcept; + explicit ImageData(CompressedPixelFormat format, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, ImageFlags flags = {}, const void* importerState = nullptr) noexcept; + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @brief @copybrief ImageData(CompressedPixelFormat, const VectorTypeFor&, DataFlags, Containers::ArrayView, ImageFlags, const void*) + * @m_deprecated_since_latest Use @ref ImageData(CompressedPixelFormat, const VectorTypeFor&, DataFlags, Containers::ArrayView, ImageFlags, const void*) + * instead. + */ + explicit CORRADE_DEPRECATED("use a constructor with an extra ImageFlags argument instead") ImageData(CompressedPixelFormat format, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, const void* importerState) noexcept: ImageData{format, size, dataFlags, data, {}, importerState} {} + #endif /** * @brief Construct a compressed image data @@ -363,12 +530,26 @@ template class ImageData { * @param format Format of compressed pixel data * @param size Image size * @param data Image data + * @param flags Image layout flags * @param importerState Importer-specific state + * @m_since_latest * * Uses @ref compressedPixelFormatWrap() internally to convert * @p format to @ref CompressedPixelFormat. + * + * For a 3D image, if @p flags contain @ref ImageFlag3D::CubeMap, the + * @p size is expected to match its restrictions. + */ + template explicit ImageData(CompressedPixelStorage storage, T format, const VectorTypeFor& size, Containers::Array&& data, ImageFlags flags = {}, const void* importerState = nullptr) noexcept; + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @brief @copybrief ImageData(CompressedPixelStorage, T, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) + * @m_deprecated_since_latest Use @ref ImageData(CompressedPixelStorage, T, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) + * instead. */ - template explicit ImageData(CompressedPixelStorage storage, T format, const VectorTypeFor& size, Containers::Array&& data, const void* importerState = nullptr) noexcept; + template explicit CORRADE_DEPRECATED("use a constructor with an extra ImageFlags argument instead") ImageData(CompressedPixelStorage storage, T format, const VectorTypeFor& size, Containers::Array&& data, const void* importerState) noexcept: ImageData{storage, format, size, std::move(data), {}, importerState} {} + #endif /** * @brief Construct a non-owned compressed image data @@ -377,16 +558,26 @@ template class ImageData { * @param size Image size * @param dataFlags Data flags * @param data View on image data + * @param flags Image layout flags * @param importerState Importer-specific state - * @m_since{2020,06} + * @m_since_latest * - * Compared to @ref ImageData(CompressedPixelStorage, T, const VectorTypeFor&, Containers::Array&&, const void*) + * Compared to @ref ImageData(CompressedPixelStorage, T, const VectorTypeFor&, Containers::Array&&, ImageFlags, const void*) * creates an instance that doesn't own the passed data. The * @p dataFlags parameter can contain @ref DataFlag::Mutable to * indicate the external data can be modified, and is expected to *not* * have @ref DataFlag::Owned set. */ - template explicit ImageData(CompressedPixelStorage storage, T format, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, const void* importerState = nullptr) noexcept; + template explicit ImageData(CompressedPixelStorage storage, T format, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, ImageFlags flags = {}, const void* importerState = nullptr) noexcept; + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @brief @copybrief ImageData(CompressedPixelStorage, T, const VectorTypeFor&, DataFlags, Containers::ArrayView, ImageFlags, const void*) + * @m_deprecated_since_latest Use @ref ImageData(CompressedPixelStorage, T, const VectorTypeFor&, DataFlags, Containers::ArrayView, ImageFlags, const void*) + * instead. + */ + template explicit CORRADE_DEPRECATED("use a constructor with an extra ImageFlags argument instead") ImageData(CompressedPixelStorage storage, T format, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, const void* importerState) noexcept: ImageData{storage, format, size, dataFlags, data, {}, importerState} {} + #endif /** * @brief Construct from existing data with attached importer state @@ -458,6 +649,12 @@ template class ImageData { */ /*implicit*/ operator BasicMutableCompressedImageView(); + /** + * @brief Layout flags + * @m_since_latest + */ + ImageFlags flags() const { return _flags; } + /** * @brief Storage of pixel data * @@ -677,12 +874,13 @@ template class ImageData { friend AbstractImporter; friend AbstractImageConverter; - explicit ImageData(CompressedPixelStorage storage, UnsignedInt format, const VectorTypeFor& size, Containers::Array&& data, const void* importerState = nullptr) noexcept; + explicit ImageData(CompressedPixelStorage storage, UnsignedInt format, const VectorTypeFor& size, Containers::Array&& data, ImageFlags flags, const void* importerState = nullptr) noexcept; - explicit ImageData(CompressedPixelStorage storage, UnsignedInt format, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, const void* importerState = nullptr) noexcept; + explicit ImageData(CompressedPixelStorage storage, UnsignedInt format, const VectorTypeFor& size, DataFlags dataFlags, Containers::ArrayView data, ImageFlags flags, const void* importerState = nullptr) noexcept; DataFlags _dataFlags; bool _compressed; + ImageFlags _flags; union { PixelStorage _storage; CompressedPixelStorage _compressedStorage; @@ -707,32 +905,32 @@ typedef ImageData<2> ImageData2D; /** @brief Three-dimensional image data */ typedef ImageData<3> ImageData3D; -template template ImageData::ImageData(const PixelStorage storage, const T format, const U formatExtra, const VectorTypeFor& size, Containers::Array&& data, const void* const importerState) noexcept: ImageData{storage, UnsignedInt(format), UnsignedInt(formatExtra), Magnum::Implementation::pixelFormatSizeAdl(format, formatExtra), size, std::move(data), importerState} { +template template ImageData::ImageData(const PixelStorage storage, const T format, const U formatExtra, const VectorTypeFor& size, Containers::Array&& data, const ImageFlags flags, const void* const importerState) noexcept: ImageData{storage, UnsignedInt(format), UnsignedInt(formatExtra), Magnum::Implementation::pixelFormatSizeAdl(format, formatExtra), size, std::move(data), flags, importerState} { static_assert(sizeof(T) <= 4 && sizeof(U) <= 4, "format types larger than 32bits are not supported"); } -template template ImageData::ImageData(const PixelStorage storage, const T format, const U formatExtra, const VectorTypeFor& size, const DataFlags dataFlags, const Containers::ArrayView data, const void* const importerState) noexcept: ImageData{storage, UnsignedInt(format), UnsignedInt(formatExtra), Magnum::Implementation::pixelFormatSizeAdl(format, formatExtra), size, dataFlags, data, importerState} { +template template ImageData::ImageData(const PixelStorage storage, const T format, const U formatExtra, const VectorTypeFor& size, const DataFlags dataFlags, const Containers::ArrayView data, const ImageFlags flags, const void* const importerState) noexcept: ImageData{storage, UnsignedInt(format), UnsignedInt(formatExtra), Magnum::Implementation::pixelFormatSizeAdl(format, formatExtra), size, dataFlags, data, flags, importerState} { static_assert(sizeof(T) <= 4 && sizeof(U) <= 4, "format types larger than 32bits are not supported"); } -template template ImageData::ImageData(const PixelStorage storage, const T format, const VectorTypeFor& size, Containers::Array&& data, const void* const importerState) noexcept: ImageData{storage, UnsignedInt(format), {}, Magnum::Implementation::pixelFormatSizeAdl(format), size, std::move(data), importerState} { +template template ImageData::ImageData(const PixelStorage storage, const T format, const VectorTypeFor& size, Containers::Array&& data, const ImageFlags flags, const void* const importerState) noexcept: ImageData{storage, UnsignedInt(format), {}, Magnum::Implementation::pixelFormatSizeAdl(format), size, std::move(data), flags, importerState} { static_assert(sizeof(T) <= 4, "format types larger than 32bits are not supported"); } -template template ImageData::ImageData(const PixelStorage storage, const T format, const VectorTypeFor& size, const DataFlags dataFlags, const Containers::ArrayView data, const void* const importerState) noexcept: ImageData{storage, UnsignedInt(format), {}, Magnum::Implementation::pixelFormatSizeAdl(format), size, dataFlags, data, importerState} { +template template ImageData::ImageData(const PixelStorage storage, const T format, const VectorTypeFor& size, const DataFlags dataFlags, const Containers::ArrayView data, const ImageFlags flags, const void* const importerState) noexcept: ImageData{storage, UnsignedInt(format), {}, Magnum::Implementation::pixelFormatSizeAdl(format), size, dataFlags, data, flags, importerState} { static_assert(sizeof(T) <= 4, "format types larger than 32bits are not supported"); } -template template ImageData::ImageData(const CompressedPixelStorage storage, const T format, const VectorTypeFor& size, Containers::Array&& data, const void* const importerState) noexcept: ImageData{storage, UnsignedInt(format), size, std::move(data), importerState} { +template template ImageData::ImageData(const CompressedPixelStorage storage, const T format, const VectorTypeFor& size, Containers::Array&& data, const ImageFlags flags, const void* const importerState) noexcept: ImageData{storage, UnsignedInt(format), size, std::move(data), flags, importerState} { static_assert(sizeof(T) <= 4, "format types larger than 32bits are not supported"); } -template template ImageData::ImageData(const CompressedPixelStorage storage, const T format, const VectorTypeFor& size, const DataFlags dataFlags, const Containers::ArrayView data, const void* const importerState) noexcept: ImageData{storage, UnsignedInt(format), size, dataFlags, data, importerState} { +template template ImageData::ImageData(const CompressedPixelStorage storage, const T format, const VectorTypeFor& size, const DataFlags dataFlags, const Containers::ArrayView data, const ImageFlags flags, const void* const importerState) noexcept: ImageData{storage, UnsignedInt(format), size, dataFlags, data, flags, importerState} { static_assert(sizeof(T) <= 4, "format types larger than 32bits are not supported"); } diff --git a/src/Magnum/Trade/Test/AbstractImporterTest.cpp b/src/Magnum/Trade/Test/AbstractImporterTest.cpp index 81b2de7c0a..535342d5c2 100644 --- a/src/Magnum/Trade/Test/AbstractImporterTest.cpp +++ b/src/Magnum/Trade/Test/AbstractImporterTest.cpp @@ -6980,7 +6980,7 @@ void AbstractImporterTest::image1D() { return {}; } Containers::Optional doImage1D(UnsignedInt id, UnsignedInt level) override { - if(id == 7 && level == 2) return ImageData1D{PixelFormat::RGBA8Unorm, {}, {}, &state}; + if(id == 7 && level == 2) return ImageData1D{PixelFormat::RGBA8Unorm, {}, {}, ImageFlags1D{}, &state}; return {}; } } importer; @@ -7302,7 +7302,7 @@ void AbstractImporterTest::image2D() { return {}; } Containers::Optional doImage2D(UnsignedInt id, UnsignedInt level) override { - if(id == 7 && level == 2) return ImageData2D{PixelFormat::RGBA8Unorm, {}, {}, &state}; + if(id == 7 && level == 2) return ImageData2D{PixelFormat::RGBA8Unorm, {}, {}, ImageFlags2D{}, &state}; return {}; } } importer; @@ -7624,7 +7624,7 @@ void AbstractImporterTest::image3D() { return {}; } Containers::Optional doImage3D(UnsignedInt id, UnsignedInt level) override { - if(id == 7 && level == 2) return ImageData3D{PixelFormat::RGBA8Unorm, {}, {}, &state}; + if(id == 7 && level == 2) return ImageData3D{PixelFormat::RGBA8Unorm, {}, {}, ImageFlags3D{}, &state}; return {}; } } importer; diff --git a/src/Magnum/Trade/Test/ImageDataTest.cpp b/src/Magnum/Trade/Test/ImageDataTest.cpp index f7d11bdac7..e92ecc4bf9 100644 --- a/src/Magnum/Trade/Test/ImageDataTest.cpp +++ b/src/Magnum/Trade/Test/ImageDataTest.cpp @@ -57,7 +57,9 @@ struct ImageDataTest: TestSuite::Tester { void constructCompressedImplementationSpecificNotOwnedFlagOwned(); void constructInvalidSize(); + void constructInvalidCubeMap(); void constructCompressedInvalidSize(); + void constructCompressedInvalidCubeMap(); void constructCopy(); @@ -127,7 +129,9 @@ ImageDataTest::ImageDataTest() { &ImageDataTest::constructCompressedImplementationSpecificNotOwnedFlagOwned, &ImageDataTest::constructInvalidSize, + &ImageDataTest::constructInvalidCubeMap, &ImageDataTest::constructCompressedInvalidSize, + &ImageDataTest::constructCompressedInvalidCubeMap, &ImageDataTest::constructCopy, @@ -202,10 +206,11 @@ void ImageDataTest::constructGeneric() { { auto data = new char[4*4]; int state{}; /* GCC 11 complains that "maybe uninitialized" w/o the {} */ - ImageData2D a{PixelFormat::RGBA8Unorm, {1, 3}, Containers::Array{data, 4*4}, &state}; + ImageData2D a{PixelFormat::RGBA8Unorm, {1, 3}, Containers::Array{data, 4*4}, ImageFlag2D::Array, &state}; CORRADE_COMPARE(a.dataFlags(), DataFlag::Owned|DataFlag::Mutable); CORRADE_VERIFY(!a.isCompressed()); + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().alignment(), 4); CORRADE_COMPARE(a.format(), PixelFormat::RGBA8Unorm); CORRADE_COMPARE(a.formatExtra(), 0); @@ -222,10 +227,11 @@ void ImageDataTest::constructGeneric() { auto data = new char[3*2]; int state{}; /* GCC 11 complains that "maybe uninitialized" w/o the {} */ ImageData2D a{PixelStorage{}.setAlignment(1), - PixelFormat::R16UI, {1, 3}, Containers::Array{data, 3*2}, &state}; + PixelFormat::R16UI, {1, 3}, Containers::Array{data, 3*2}, ImageFlag2D::Array, &state}; CORRADE_COMPARE(a.dataFlags(), DataFlag::Owned|DataFlag::Mutable); CORRADE_VERIFY(!a.isCompressed()); + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), PixelFormat::R16UI); CORRADE_COMPARE(a.formatExtra(), 0); @@ -247,10 +253,11 @@ void ImageDataTest::constructImplementationSpecific() { auto data = new char[3*12]; int state{}; /* GCC 11 complains that "maybe uninitialized" w/o the {} */ ImageData2D a{PixelStorage{}.setAlignment(1), - Vk::PixelFormat::R32G32B32F, {1, 3}, Containers::Array{data, 3*12}, &state}; + Vk::PixelFormat::R32G32B32F, {1, 3}, Containers::Array{data, 3*12}, ImageFlag2D::Array, &state}; CORRADE_COMPARE(a.dataFlags(), DataFlag::Owned|DataFlag::Mutable); CORRADE_VERIFY(!a.isCompressed()); + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), pixelFormatWrap(Vk::PixelFormat::R32G32B32F)); CORRADE_COMPARE(a.formatExtra(), 0); @@ -270,10 +277,11 @@ void ImageDataTest::constructImplementationSpecific() { auto data = new char[3*6]; int state{}; /* GCC 11 complains that "maybe uninitialized" w/o the {} */ ImageData2D a{PixelStorage{}.setAlignment(1), - GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, Containers::Array{data, 3*6}, &state}; + GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, Containers::Array{data, 3*6}, ImageFlag2D::Array, &state}; CORRADE_COMPARE(a.dataFlags(), DataFlag::Owned|DataFlag::Mutable); CORRADE_VERIFY(!a.isCompressed()); + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(a.formatExtra(), UnsignedInt(GL::PixelType::UnsignedShort)); CORRADE_COMPARE(a.pixelSize(), 6); @@ -291,10 +299,11 @@ void ImageDataTest::constructImplementationSpecific() { { auto data = new char[3*6]; int state{}; /* GCC 11 complains that "maybe uninitialized" w/o the {} */ - ImageData2D a{PixelStorage{}.setAlignment(1), 666, 1337, 6, {1, 3}, Containers::Array{data, 3*6}, &state}; + ImageData2D a{PixelStorage{}.setAlignment(1), 666, 1337, 6, {1, 3}, Containers::Array{data, 3*6}, ImageFlag2D::Array, &state}; CORRADE_COMPARE(a.dataFlags(), DataFlag::Owned|DataFlag::Mutable); CORRADE_VERIFY(!a.isCompressed()); + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(a.formatExtra(), UnsignedInt(GL::PixelType::UnsignedShort)); @@ -315,10 +324,11 @@ void ImageDataTest::constructCompressedGeneric() { auto data = new char[8]; int state{}; /* GCC 11 complains that "maybe uninitialized" w/o the {} */ ImageData2D a{CompressedPixelFormat::Bc1RGBAUnorm, {4, 4}, - Containers::Array{data, 8}, &state}; + Containers::Array{data, 8}, ImageFlag2D::Array, &state}; CORRADE_COMPARE(a.dataFlags(), DataFlag::Owned|DataFlag::Mutable); CORRADE_VERIFY(a.isCompressed()); + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.compressedStorage().compressedBlockSize(), Vector3i{0}); CORRADE_COMPARE(a.compressedFormat(), CompressedPixelFormat::Bc1RGBAUnorm); CORRADE_COMPARE(a.size(), (Vector2i{4, 4})); @@ -332,10 +342,11 @@ void ImageDataTest::constructCompressedGeneric() { int state{}; /* GCC 11 complains that "maybe uninitialized" w/o the {} */ ImageData2D a{CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), CompressedPixelFormat::Bc1RGBAUnorm, {4, 4}, - Containers::Array{data, 8}, &state}; + Containers::Array{data, 8}, ImageFlag2D::Array, &state}; CORRADE_COMPARE(a.dataFlags(), DataFlag::Owned|DataFlag::Mutable); CORRADE_VERIFY(a.isCompressed()); + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.compressedStorage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(a.compressedFormat(), CompressedPixelFormat::Bc1RGBAUnorm); CORRADE_COMPARE(a.size(), Vector2i(4, 4)); @@ -354,10 +365,11 @@ void ImageDataTest::constructCompressedImplementationSpecific() { int state{}; /* GCC 11 complains that "maybe uninitialized" w/o the {} */ ImageData2D a{CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 4}, - Containers::Array{data, 8}, &state}; + Containers::Array{data, 8}, ImageFlag2D::Array, &state}; CORRADE_COMPARE(a.dataFlags(), DataFlag::Owned|DataFlag::Mutable); CORRADE_VERIFY(a.isCompressed()); + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.compressedStorage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(a.compressedFormat(), compressedPixelFormatWrap(GL::CompressedPixelFormat::RGBS3tcDxt1)); CORRADE_COMPARE(a.size(), (Vector2i{4, 4})); @@ -378,10 +390,11 @@ void ImageDataTest::constructGenericNotOwned() { { char data[4*4]; int state; - ImageData2D a{PixelFormat::RGBA8Unorm, {1, 3}, instanceData.dataFlags, data, &state}; + ImageData2D a{PixelFormat::RGBA8Unorm, {1, 3}, instanceData.dataFlags, data, ImageFlag2D::Array, &state}; CORRADE_COMPARE(a.dataFlags(), instanceData.dataFlags); CORRADE_VERIFY(!a.isCompressed()); + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().alignment(), 4); CORRADE_COMPARE(a.format(), PixelFormat::RGBA8Unorm); CORRADE_COMPARE(a.formatExtra(), 0); @@ -400,10 +413,11 @@ void ImageDataTest::constructGenericNotOwned() { char data[3*2]; int state; ImageData2D a{PixelStorage{}.setAlignment(1), - PixelFormat::R16UI, {1, 3}, instanceData.dataFlags, data, &state}; + PixelFormat::R16UI, {1, 3}, instanceData.dataFlags, data, ImageFlag2D::Array, &state}; CORRADE_COMPARE(a.dataFlags(), instanceData.dataFlags); CORRADE_VERIFY(!a.isCompressed()); + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), PixelFormat::R16UI); CORRADE_COMPARE(a.formatExtra(), 0); @@ -430,10 +444,11 @@ void ImageDataTest::constructImplementationSpecificNotOwned() { char data[3*12]; int state; ImageData2D a{PixelStorage{}.setAlignment(1), - Vk::PixelFormat::R32G32B32F, {1, 3}, instanceData.dataFlags, data, &state}; + Vk::PixelFormat::R32G32B32F, {1, 3}, instanceData.dataFlags, data, ImageFlag2D::Array, &state}; CORRADE_COMPARE(a.dataFlags(), instanceData.dataFlags); CORRADE_VERIFY(!a.isCompressed()); + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), pixelFormatWrap(Vk::PixelFormat::R32G32B32F)); CORRADE_COMPARE(a.formatExtra(), 0); @@ -455,10 +470,11 @@ void ImageDataTest::constructImplementationSpecificNotOwned() { char data[3*6]; int state; ImageData2D a{PixelStorage{}.setAlignment(1), - GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, instanceData.dataFlags, data, &state}; + GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, instanceData.dataFlags, data, ImageFlag2D::Array, &state}; CORRADE_COMPARE(a.dataFlags(), instanceData.dataFlags); CORRADE_VERIFY(!a.isCompressed()); + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(a.formatExtra(), UnsignedInt(GL::PixelType::UnsignedShort)); CORRADE_COMPARE(a.pixelSize(), 6); @@ -478,10 +494,11 @@ void ImageDataTest::constructImplementationSpecificNotOwned() { { char data[3*6]; int state; - ImageData2D a{PixelStorage{}.setAlignment(1), 666, 1337, 6, {1, 3}, instanceData.dataFlags, data, &state}; + ImageData2D a{PixelStorage{}.setAlignment(1), 666, 1337, 6, {1, 3}, instanceData.dataFlags, data, ImageFlag2D::Array, &state}; CORRADE_COMPARE(a.dataFlags(), instanceData.dataFlags); CORRADE_VERIFY(!a.isCompressed()); + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(a.formatExtra(), UnsignedInt(GL::PixelType::UnsignedShort)); @@ -507,10 +524,11 @@ void ImageDataTest::constructCompressedGenericNotOwned() { char data[8]; int state; ImageData2D a{CompressedPixelFormat::Bc1RGBAUnorm, {4, 4}, - instanceData.dataFlags, data, &state}; + instanceData.dataFlags, data, ImageFlag2D::Array, &state}; CORRADE_COMPARE(a.dataFlags(), instanceData.dataFlags); CORRADE_VERIFY(a.isCompressed()); + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.compressedStorage().compressedBlockSize(), Vector3i{0}); CORRADE_COMPARE(a.compressedFormat(), CompressedPixelFormat::Bc1RGBAUnorm); CORRADE_COMPARE(a.size(), (Vector2i{4, 4})); @@ -526,10 +544,11 @@ void ImageDataTest::constructCompressedGenericNotOwned() { int state; ImageData2D a{CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), CompressedPixelFormat::Bc1RGBAUnorm, {4, 4}, - instanceData.dataFlags, data, &state}; + instanceData.dataFlags, data, ImageFlag2D::Array, &state}; CORRADE_COMPARE(a.dataFlags(), instanceData.dataFlags); CORRADE_VERIFY(a.isCompressed()); + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.compressedStorage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(a.compressedFormat(), CompressedPixelFormat::Bc1RGBAUnorm); CORRADE_COMPARE(a.size(), Vector2i(4, 4)); @@ -553,10 +572,11 @@ void ImageDataTest::constructCompressedImplementationSpecificNotOwned() { int state; ImageData2D a{CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 4}, - instanceData.dataFlags, data, &state}; + instanceData.dataFlags, data, ImageFlag2D::Array, &state}; CORRADE_COMPARE(a.dataFlags(), instanceData.dataFlags); CORRADE_VERIFY(a.isCompressed()); + CORRADE_COMPARE(a.flags(), ImageFlag2D::Array); CORRADE_COMPARE(a.compressedStorage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(a.compressedFormat(), compressedPixelFormatWrap(GL::CompressedPixelFormat::RGBS3tcDxt1)); CORRADE_COMPARE(a.size(), (Vector2i{4, 4})); @@ -649,6 +669,24 @@ void ImageDataTest::constructInvalidSize() { CORRADE_COMPARE(out.str(), "Trade::ImageData: data too small, got 9 but expected at least 12 bytes\n"); } +void ImageDataTest::constructInvalidCubeMap() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + std::ostringstream out; + Error redirectError{&out}; + ImageData3D{PixelFormat::RGBA8Unorm, {3, 3, 5}, Containers::Array{3*3*5*4}, ImageFlag3D::CubeMap}; + ImageData3D{PixelFormat::RGBA8Unorm, {3, 4, 6}, Containers::Array{3*4*6*4}, ImageFlag3D::CubeMap}; + ImageData3D{PixelFormat::RGBA8Unorm, {3, 3, 17}, Containers::Array{3*3*17*4}, ImageFlag3D::CubeMap |ImageFlag3D::Array}; + ImageData3D{PixelFormat::RGBA8Unorm, {4, 3, 18}, Containers::Array{4*3*18*4}, ImageFlag3D::CubeMap |ImageFlag3D::Array}; + CORRADE_COMPARE(out.str(), + "Trade::ImageData: expected exactly 6 faces for a cube map, got 5\n" + "Trade::ImageData: expected square faces for a cube map, got {3, 4}\n" + "Trade::ImageData: expected a multiple of 6 faces for a cube map array, got 17\n" + "Trade::ImageData: expected square faces for a cube map, got {4, 3}\n"); +} + void ImageDataTest::constructCompressedInvalidSize() { CORRADE_EXPECT_FAIL("Size checking for compressed image data is not implemented yet."); @@ -668,6 +706,24 @@ void ImageDataTest::constructCompressedInvalidSize() { } } +void ImageDataTest::constructCompressedInvalidCubeMap() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + std::ostringstream out; + Error redirectError{&out}; + ImageData3D{CompressedPixelFormat::Bc1RGBAUnorm, {3, 3, 5}, Containers::Array{8*5}, ImageFlag3D::CubeMap}; + ImageData3D{CompressedPixelFormat::Bc1RGBAUnorm, {3, 4, 6}, Containers::Array{8*6}, ImageFlag3D::CubeMap}; + ImageData3D{CompressedPixelFormat::Bc1RGBAUnorm, {3, 3, 17}, Containers::Array{8*17}, ImageFlag3D::CubeMap |ImageFlag3D::Array}; + ImageData3D{CompressedPixelFormat::Bc1RGBAUnorm, {4, 3, 18}, Containers::Array{8*18}, ImageFlag3D::CubeMap |ImageFlag3D::Array}; + CORRADE_COMPARE(out.str(), + "Trade::ImageData: expected exactly 6 faces for a cube map, got 5\n" + "Trade::ImageData: expected square faces for a cube map, got {3, 4}\n" + "Trade::ImageData: expected a multiple of 6 faces for a cube map array, got 17\n" + "Trade::ImageData: expected square faces for a cube map, got {4, 3}\n"); +} + void ImageDataTest::constructCopy() { CORRADE_VERIFY(!std::is_copy_constructible{}); CORRADE_VERIFY(!std::is_copy_assignable{}); @@ -677,7 +733,7 @@ void ImageDataTest::constructMoveGeneric() { auto data = new char[3*16]; int state{}; /* GCC 11 complains that "maybe uninitialized" w/o the {} */ ImageData2D a{PixelStorage{}.setAlignment(1), - PixelFormat::RGBA32F, {1, 3}, Containers::Array{data, 3*16}, &state}; + PixelFormat::RGBA32F, {1, 3}, Containers::Array{data, 3*16}, ImageFlag2D::Array, &state}; ImageData2D b(std::move(a)); CORRADE_COMPARE(a.data(), static_cast(nullptr)); @@ -685,6 +741,7 @@ void ImageDataTest::constructMoveGeneric() { CORRADE_COMPARE(b.dataFlags(), DataFlag::Owned|DataFlag::Mutable); CORRADE_VERIFY(!b.isCompressed()); + CORRADE_COMPARE(b.flags(), ImageFlag2D::Array); CORRADE_COMPARE(b.storage().alignment(), 1); CORRADE_COMPARE(b.format(), PixelFormat::RGBA32F); CORRADE_COMPARE(b.formatExtra(), 0); @@ -703,6 +760,7 @@ void ImageDataTest::constructMoveGeneric() { CORRADE_COMPARE(c.dataFlags(), DataFlag::Owned|DataFlag::Mutable); CORRADE_VERIFY(!c.isCompressed()); + CORRADE_COMPARE(c.flags(), ImageFlag2D::Array); CORRADE_COMPARE(c.storage().alignment(), 1); CORRADE_COMPARE(c.format(), PixelFormat::RGBA32F); CORRADE_COMPARE(c.formatExtra(), 0); @@ -720,7 +778,7 @@ void ImageDataTest::constructMoveImplementationSpecific() { auto data = new char[3*6]; int state{}; /* GCC 11 complains that "maybe uninitialized" w/o the {} */ ImageData2D a{PixelStorage{}.setAlignment(1), - GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, Containers::Array{data, 3*6}, &state}; + GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, Containers::Array{data, 3*6}, ImageFlag2D::Array, &state}; ImageData2D b(std::move(a)); CORRADE_COMPARE(a.data(), static_cast(nullptr)); @@ -728,6 +786,7 @@ void ImageDataTest::constructMoveImplementationSpecific() { CORRADE_COMPARE(b.dataFlags(), DataFlag::Owned|DataFlag::Mutable); CORRADE_VERIFY(!b.isCompressed()); + CORRADE_COMPARE(b.flags(), ImageFlag2D::Array); CORRADE_COMPARE(b.storage().alignment(), 1); CORRADE_COMPARE(b.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(b.formatExtra(), 1337); @@ -747,6 +806,7 @@ void ImageDataTest::constructMoveImplementationSpecific() { CORRADE_COMPARE(c.dataFlags(), DataFlag::Owned|DataFlag::Mutable); CORRADE_VERIFY(!c.isCompressed()); + CORRADE_COMPARE(c.flags(), ImageFlag2D::Array); CORRADE_COMPARE(c.storage().alignment(), 1); CORRADE_COMPARE(c.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(c.formatExtra(), 1337); @@ -762,7 +822,7 @@ void ImageDataTest::constructMoveCompressedGeneric() { int state{}; /* GCC 11 complains that "maybe uninitialized" w/o the {} */ ImageData2D a{ CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), - CompressedPixelFormat::Bc3RGBAUnorm, {4, 4}, Containers::Array{data, 8}, &state}; + CompressedPixelFormat::Bc3RGBAUnorm, {4, 4}, Containers::Array{data, 8}, ImageFlag2D::Array, &state}; ImageData2D b{std::move(a)}; CORRADE_COMPARE(a.data(), static_cast(nullptr)); @@ -770,6 +830,7 @@ void ImageDataTest::constructMoveCompressedGeneric() { CORRADE_COMPARE(b.dataFlags(), DataFlag::Owned|DataFlag::Mutable); CORRADE_VERIFY(b.isCompressed()); + CORRADE_COMPARE(b.flags(), ImageFlag2D::Array); CORRADE_COMPARE(b.compressedStorage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(b.compressedFormat(), CompressedPixelFormat::Bc3RGBAUnorm); CORRADE_COMPARE(b.size(), (Vector2i{4, 4})); @@ -786,6 +847,7 @@ void ImageDataTest::constructMoveCompressedGeneric() { CORRADE_COMPARE(c.dataFlags(), DataFlag::Owned|DataFlag::Mutable); CORRADE_VERIFY(c.isCompressed()); + CORRADE_COMPARE(c.flags(), ImageFlag2D::Array); CORRADE_COMPARE(c.compressedStorage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(c.compressedFormat(), CompressedPixelFormat::Bc3RGBAUnorm); CORRADE_COMPARE(c.size(), (Vector2i{4, 4})); @@ -799,7 +861,7 @@ void ImageDataTest::constructMoveCompressedImplementationSpecific() { int state{}; /* GCC 11 complains that "maybe uninitialized" w/o the {} */ ImageData2D a{ CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), - GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 4}, Containers::Array{data, 8}, &state}; + GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 4}, Containers::Array{data, 8}, ImageFlag2D::Array, &state}; ImageData2D b{std::move(a)}; CORRADE_COMPARE(a.data(), static_cast(nullptr)); @@ -807,6 +869,7 @@ void ImageDataTest::constructMoveCompressedImplementationSpecific() { CORRADE_COMPARE(b.dataFlags(), DataFlag::Owned|DataFlag::Mutable); CORRADE_VERIFY(b.isCompressed()); + CORRADE_COMPARE(b.flags(), ImageFlag2D::Array); CORRADE_COMPARE(b.compressedStorage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(b.compressedFormat(), compressedPixelFormatWrap(GL::CompressedPixelFormat::RGBS3tcDxt1)); CORRADE_COMPARE(b.size(), (Vector2i{4, 4})); @@ -823,6 +886,7 @@ void ImageDataTest::constructMoveCompressedImplementationSpecific() { CORRADE_COMPARE(c.dataFlags(), DataFlag::Owned|DataFlag::Mutable); CORRADE_VERIFY(c.isCompressed()); + CORRADE_COMPARE(c.flags(), ImageFlag2D::Array); CORRADE_COMPARE(c.compressedStorage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(c.compressedFormat(), compressedPixelFormatWrap(GL::CompressedPixelFormat::RGBS3tcDxt1)); CORRADE_COMPARE(c.size(), (Vector2i{4, 4})); @@ -836,7 +900,7 @@ void ImageDataTest::constructMoveAttachState() { /* GCC 11 pointlessly complains that "maybe uninitialized" w/o the {} */ int stateOld{}, stateNew{}; ImageData2D a{PixelStorage{}.setAlignment(1), - GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, Containers::Array{data, 3*6}, &stateOld}; + GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, Containers::Array{data, 3*6}, ImageFlag2D::Array, &stateOld}; ImageData2D b{std::move(a), &stateNew}; CORRADE_COMPARE(a.data(), static_cast(nullptr)); @@ -844,6 +908,7 @@ void ImageDataTest::constructMoveAttachState() { CORRADE_COMPARE(b.dataFlags(), DataFlag::Owned|DataFlag::Mutable); CORRADE_VERIFY(!b.isCompressed()); + CORRADE_COMPARE(b.flags(), ImageFlag2D::Array); CORRADE_COMPARE(b.storage().alignment(), 1); CORRADE_COMPARE(b.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(b.formatExtra(), 1337); @@ -860,7 +925,7 @@ void ImageDataTest::constructMoveCompressedAttachState() { int stateOld{}, stateNew{}; ImageData2D a{ CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), - GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 4}, Containers::Array{data, 8}, &stateOld}; + GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 4}, Containers::Array{data, 8}, ImageFlag2D::Array, &stateOld}; ImageData2D b{std::move(a), &stateNew}; CORRADE_COMPARE(a.data(), static_cast(nullptr)); @@ -868,6 +933,7 @@ void ImageDataTest::constructMoveCompressedAttachState() { CORRADE_COMPARE(b.dataFlags(), DataFlag::Owned|DataFlag::Mutable); CORRADE_VERIFY(b.isCompressed()); + CORRADE_COMPARE(b.flags(), ImageFlag2D::Array); CORRADE_COMPARE(b.compressedStorage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(b.compressedFormat(), compressedPixelFormatWrap(GL::CompressedPixelFormat::RGBS3tcDxt1)); CORRADE_COMPARE(b.size(), (Vector2i{4, 4})); @@ -881,9 +947,10 @@ template void ImageDataTest::toViewGeneric() { auto data = new char[3*4]; typename MutabilityTraits::ImageType a{PixelStorage{}.setAlignment(1), - PixelFormat::RG16I, {1, 3}, Containers::Array{data, 3*4}}; + PixelFormat::RG16I, {1, 3}, Containers::Array{data, 3*4}, ImageFlag2D::Array}; ImageView<2, T> b = a; + CORRADE_COMPARE(b.flags(), ImageFlag2D::Array); CORRADE_COMPARE(b.storage().alignment(), 1); CORRADE_COMPARE(b.format(), PixelFormat::RG16I); CORRADE_COMPARE(b.formatExtra(), 0); @@ -897,9 +964,10 @@ template void ImageDataTest::toViewImplementationSpecific() { auto data = new char[3*6]; typename MutabilityTraits::ImageType a{PixelStorage{}.setAlignment(1), - GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, Containers::Array{data, 3*6}}; + GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, Containers::Array{data, 3*6}, ImageFlag2D::Array}; ImageView<2, T> b = a; + CORRADE_COMPARE(b.flags(), ImageFlag2D::Array); CORRADE_COMPARE(b.storage().alignment(), 1); CORRADE_COMPARE(b.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(b.formatExtra(), 1337); @@ -914,9 +982,10 @@ template void ImageDataTest::toViewCompressedGeneric() { auto data = new char[8]; typename MutabilityTraits::ImageType a{ CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), - CompressedPixelFormat::Bc1RGBUnorm, {4, 4}, Containers::Array{data, 8}}; + CompressedPixelFormat::Bc1RGBUnorm, {4, 4}, Containers::Array{data, 8}, ImageFlag2D::Array}; CompressedImageView<2, T> b = a; + CORRADE_COMPARE(b.flags(), ImageFlag2D::Array); CORRADE_COMPARE(b.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(b.format(), CompressedPixelFormat::Bc1RGBUnorm); CORRADE_COMPARE(b.size(), (Vector2i{4, 4})); @@ -930,9 +999,10 @@ template void ImageDataTest::toViewCompressedImplementationSpecific() { auto data = new char[8]; typename MutabilityTraits::ImageType a{ CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), - GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 4}, Containers::Array{data, 8}}; + GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 4}, Containers::Array{data, 8}, ImageFlag2D::Array}; CompressedImageView<2, T> b = a; + CORRADE_COMPARE(b.flags(), ImageFlag2D::Array); CORRADE_COMPARE(b.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(b.format(), compressedPixelFormatWrap(GL::CompressedPixelFormat::RGBS3tcDxt1)); CORRADE_COMPARE(b.size(), (Vector2i{4, 4}));