From 41b975cb694a1bc80a6b0b253e3a650364e908ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Fri, 19 Jul 2019 16:25:36 +0200 Subject: [PATCH] New Mutable[Compressed]ImageView types for non-const image data views. --- doc/changelog.dox | 3 + src/Magnum/GL/Texture.h | 8 +- src/Magnum/GL/TextureArray.h | 8 +- src/Magnum/Image.h | 28 +- src/Magnum/ImageView.cpp | 48 ++-- src/Magnum/ImageView.h | 294 ++++++++++++++++----- src/Magnum/Magnum.h | 24 +- src/Magnum/Test/ImageTest.cpp | 66 +++-- src/Magnum/Test/ImageViewTest.cpp | 328 ++++++++++++++++-------- src/Magnum/Trade/ImageData.cpp | 26 +- src/Magnum/Trade/ImageData.h | 8 +- src/Magnum/Trade/Test/ImageDataTest.cpp | 64 +++-- 12 files changed, 629 insertions(+), 276 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index 0bc1661a8..a37c97322 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -46,6 +46,9 @@ See also: - New @ref Image::pixels(), @ref ImageView::pixels() and @ref Trade::ImageData::pixels() accessors for convenient direct access to pixel data of any image +- New @ref MutableImageView2D "MutableImageView*D" and + @ref CompressedMutableImageView2D "CompressedMutableImageView*D" types for + mutable views onto image data @subsubsection changelog-latest-new-audio Audio library diff --git a/src/Magnum/GL/Texture.h b/src/Magnum/GL/Texture.h index 67929c294..aaa04f80e 100644 --- a/src/Magnum/GL/Texture.h +++ b/src/Magnum/GL/Texture.h @@ -1037,7 +1037,7 @@ template class Texture: public AbstractTexture { * @deprecated_gl Prefer to use @ref setStorage() and @ref setSubImage() * instead. */ - Texture& setImage(Int level, TextureFormat internalFormat, const ImageView& image) { + Texture& setImage(Int level, TextureFormat internalFormat, const ImageView& image) { DataHelper::setImage(*this, level, internalFormat, image); return *this; } @@ -1093,7 +1093,7 @@ template class Texture: public AbstractTexture { * @deprecated_gl Prefer to use @ref setStorage() and * @ref setCompressedSubImage() instead. */ - Texture& setCompressedImage(Int level, const CompressedImageView& image) { + Texture& setCompressedImage(Int level, const CompressedImageView& image) { DataHelper::setCompressedImage(*this, level, image); return *this; } @@ -1167,7 +1167,7 @@ template class Texture: public AbstractTexture { * able to use @ref setStorage() as it uses implicit @ref PixelType * value. */ - Texture& setSubImage(Int level, const VectorTypeFor& offset, const ImageView& image) { + Texture& setSubImage(Int level, const VectorTypeFor& offset, const ImageView& image) { DataHelper::setSubImage(*this, level, offset, image); return *this; } @@ -1219,7 +1219,7 @@ template class Texture: public AbstractTexture { * @requires_gl Non-default @ref CompressedPixelStorage is not * available in OpenGL ES and WebGL. */ - Texture& setCompressedSubImage(Int level, const VectorTypeFor& offset, const CompressedImageView& image) { + Texture& setCompressedSubImage(Int level, const VectorTypeFor& offset, const CompressedImageView& image) { DataHelper::setCompressedSubImage(*this, level, offset, image); return *this; } diff --git a/src/Magnum/GL/TextureArray.h b/src/Magnum/GL/TextureArray.h index bb98ba7ac..dae031470 100644 --- a/src/Magnum/GL/TextureArray.h +++ b/src/Magnum/GL/TextureArray.h @@ -699,7 +699,7 @@ template class TextureArray: public AbstractTexture { * @deprecated_gl Prefer to use @ref setStorage() and @ref setSubImage() * instead. */ - TextureArray& setImage(Int level, TextureFormat internalFormat, const ImageView& image) { + TextureArray& setImage(Int level, TextureFormat internalFormat, const ImageView& image) { DataHelper::setImage(*this, level, internalFormat, image); return *this; } @@ -734,7 +734,7 @@ template class TextureArray: public AbstractTexture { * @deprecated_gl Prefer to use @ref setStorage() and * @ref setCompressedSubImage() instead. */ - TextureArray& setCompressedImage(Int level, const CompressedImageView& image) { + TextureArray& setCompressedImage(Int level, const CompressedImageView& image) { DataHelper::setCompressedImage(*this, level, image); return *this; } @@ -781,7 +781,7 @@ template class TextureArray: public AbstractTexture { * eventually @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and * @fn_gl_keyword{TexSubImage2D} / @fn_gl_keyword{TexSubImage3D} */ - TextureArray& setSubImage(Int level, const VectorTypeFor& offset, const ImageView& image) { + TextureArray& setSubImage(Int level, const VectorTypeFor& offset, const ImageView& image) { DataHelper::setSubImage(*this, level, offset, image); return *this; } @@ -818,7 +818,7 @@ template class TextureArray: public AbstractTexture { * @requires_gl Non-default @ref CompressedPixelStorage is not * available in OpenGL ES and WebGL. */ - TextureArray& setCompressedSubImage(Int level, const VectorTypeFor& offset, const CompressedImageView& image) { + TextureArray& setCompressedSubImage(Int level, const VectorTypeFor& offset, const CompressedImageView& image) { DataHelper::setCompressedSubImage(*this, level, offset, image); return *this; } diff --git a/src/Magnum/Image.h b/src/Magnum/Image.h index 8dc9c709f..4b4ebb75a 100644 --- a/src/Magnum/Image.h +++ b/src/Magnum/Image.h @@ -307,7 +307,9 @@ template class Image { /** @brief Conversion to view */ /* Not restricted to const&, because we might want to pass the view to another function in an oneliner (e.g. saving screenshot) */ - /*implicit*/ operator ImageView() const; + /*implicit*/ operator ImageView(); + /** @overload */ + /*implicit*/ operator ImageView() const; /** @brief Storage of pixel data */ PixelStorage storage() const { return _storage; } @@ -566,7 +568,11 @@ template class CompressedImage { CompressedImage& operator=(CompressedImage&& other) noexcept; /** @brief Conversion to view */ - /*implicit*/ operator CompressedImageView() const; + /* Not restricted to const&, because we might want to pass the view to + another function in an oneliner (e.g. saving screenshot) */ + /*implicit*/ operator CompressedImageView(); + /** @overload */ + /*implicit*/ operator CompressedImageView() const; /** @brief Storage of compressed pixel data */ CompressedPixelStorage storage() const { return _storage; } @@ -700,14 +706,20 @@ template inline CompressedImage& CompressedI return *this; } -template inline Image::operator ImageView() const -{ - return ImageView{_storage, _format, _formatExtra, _pixelSize, _size, _data}; +template inline Image::operator ImageView() { + return ImageView{_storage, _format, _formatExtra, _pixelSize, _size, _data}; } -template inline CompressedImage::operator CompressedImageView() const -{ - return CompressedImageView{_storage, _format, _size, _data}; +template inline Image::operator ImageView() const { + return ImageView{_storage, _format, _formatExtra, _pixelSize, _size, _data}; +} + +template inline CompressedImage::operator CompressedImageView() { + return CompressedImageView{_storage, _format, _size, _data}; +} + +template inline CompressedImage::operator CompressedImageView() const { + return CompressedImageView{_storage, _format, _size, _data}; } template inline Containers::Array Image::release() { diff --git a/src/Magnum/ImageView.cpp b/src/Magnum/ImageView.cpp index 3b33f8894..a1a4c35a7 100644 --- a/src/Magnum/ImageView.cpp +++ b/src/Magnum/ImageView.cpp @@ -30,45 +30,51 @@ namespace Magnum { -template ImageView::ImageView(const PixelStorage storage, const PixelFormat format, const VectorTypeFor& size, const Containers::ArrayView data) noexcept: ImageView{storage, format, {}, Magnum::pixelSize(format), size, data} {} +template ImageView::ImageView(const PixelStorage storage, const PixelFormat format, const VectorTypeFor& size, const Containers::ArrayView data) noexcept: ImageView{storage, format, {}, Magnum::pixelSize(format), size, data} {} -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) noexcept: ImageView{storage, pixelFormatWrap(format), formatExtra, pixelSize, size, data} {} -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) noexcept: _storage{storage}, _format{format}, _formatExtra{formatExtra}, _pixelSize{pixelSize}, _size{size}, _data{reinterpret_cast(data.data()), data.size()} { CORRADE_ASSERT(!_data || Implementation::imageDataSize(*this) <= _data.size(), "ImageView::ImageView(): data too small, got" << _data.size() << "but expected at least" << Implementation::imageDataSize(*this) << "bytes", ); } -template ImageView::ImageView(const PixelStorage storage, const PixelFormat format, const VectorTypeFor& size) noexcept: ImageView{storage, format, {}, Magnum::pixelSize(format), size} {} +template ImageView::ImageView(const PixelStorage storage, const PixelFormat format, const VectorTypeFor& size) noexcept: ImageView{storage, format, {}, Magnum::pixelSize(format), size} {} -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) noexcept: ImageView{storage, pixelFormatWrap(format), formatExtra, pixelSize, size} {} -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) noexcept: _storage{storage}, _format{format}, _formatExtra{formatExtra}, _pixelSize{pixelSize}, _size{size}, _data{nullptr} {} -template void ImageView::setData(const Containers::ArrayView data) { +template void ImageView::setData(const Containers::ArrayView data) { CORRADE_ASSERT(Implementation::imageDataSize(*this) <= data.size(), "ImageView::setData(): data too small, got" << data.size() << "but expected at least" << Implementation::imageDataSize(*this) << "bytes", ); - _data = {reinterpret_cast(data.data()), data.size()}; + _data = {reinterpret_cast(data.data()), data.size()}; } -template Containers::StridedArrayView ImageView::pixels() const { - return Implementation::imagePixelView(*this); +template auto ImageView::pixels() const -> Containers::StridedArrayView { + return Implementation::imagePixelView(*this); } -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) 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) noexcept: _storage{storage}, _format{format}, _size{size} {} +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 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) noexcept: CompressedImageView{storage, compressedPixelFormatWrap(format), size, data} {} -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) noexcept: CompressedImageView{storage, compressedPixelFormatWrap(format), size} {} #ifndef DOXYGEN_GENERATING_OUTPUT -template class MAGNUM_EXPORT ImageView<1>; -template class MAGNUM_EXPORT ImageView<2>; -template class MAGNUM_EXPORT ImageView<3>; - -template class MAGNUM_EXPORT CompressedImageView<1>; -template class MAGNUM_EXPORT CompressedImageView<2>; -template class MAGNUM_EXPORT CompressedImageView<3>; +template class MAGNUM_EXPORT ImageView<1, const char>; +template class MAGNUM_EXPORT ImageView<2, const char>; +template class MAGNUM_EXPORT ImageView<3, const char>; +template class MAGNUM_EXPORT ImageView<1, char>; +template class MAGNUM_EXPORT ImageView<2, char>; +template class MAGNUM_EXPORT ImageView<3, char>; + +template class MAGNUM_EXPORT CompressedImageView<1, const char>; +template class MAGNUM_EXPORT CompressedImageView<2, const char>; +template class MAGNUM_EXPORT CompressedImageView<3, const char>; +template class MAGNUM_EXPORT CompressedImageView<1, char>; +template class MAGNUM_EXPORT CompressedImageView<2, char>; +template class MAGNUM_EXPORT CompressedImageView<3, char>; #endif } diff --git a/src/Magnum/ImageView.h b/src/Magnum/ImageView.h index da8e0292f..b8ef0d0b8 100644 --- a/src/Magnum/ImageView.h +++ b/src/Magnum/ImageView.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class @ref Magnum::ImageView, @ref Magnum::CompressedImageView, typedef @ref Magnum::ImageView1D, @ref Magnum::ImageView2D, @ref Magnum::ImageView3D, @ref Magnum::CompressedImageView1D, @ref Magnum::CompressedImageView2D, @ref Magnum::CompressedImageView3D + * @brief Class @ref Magnum::ImageView, @ref Magnum::CompressedImageView, typedef @ref Magnum::ImageView1D, @ref Magnum::ImageView2D, @ref Magnum::ImageView3D, @ref Magnum::MutableImageView1D, @ref Magnum::MutableImageView2D, @ref Magnum::MutableImageView3D, @ref Magnum::CompressedImageView1D, @ref Magnum::CompressedImageView2D, @ref Magnum::CompressedImageView3D, @ref Magnum::MutableCompressedImageView1D, @ref Magnum::MutableCompressedImageView2D, @ref Magnum::MutableCompressedImageView3D */ #include @@ -78,6 +78,16 @@ sub-rectangle of a 75x75 8-bit RGB image , with rows aligned to four bytes: @snippet Magnum.cpp ImageView-usage-storage +@section ImageView-mutable Data mutability + +When using e.g. the @ref ImageView2D typedef, the viewed data are immutable. +This is the most common use case, in order to be able to mutate the underlying +data (for example in order to read into a pre-allocated memory), use +@ref MutableImageView2D and friends instead. @ref Image and +@ref Trade::ImageData are convertible to either of these. Similarly to +@ref Corrade::Containers::ArrayView etc., a mutable view is also implicitly +convertible to a const one. + @subsection ImageView-usage-implementation-specific Implementation-specific formats For known graphics APIs, there's a set of utility functions converting from @@ -114,10 +124,35 @@ Metal-specific format identifier: @snippet Magnum.cpp ImageView-usage-metal @see @ref ImageView1D, @ref ImageView2D, @ref ImageView3D, + @ref MutableImageView1D, @ref MutableImageView2D, @ref MutableImageView3D, @ref Image-pixel-views */ -template class ImageView { +template class ImageView { public: + /* Pointer arithmetic relies on the type being a single byte */ + static_assert(std::is_same::value ||std::is_same::value, + "image view type can be either char or const char"); + + /** + * @brief Raw data type + * + * @cpp const char @ce for @ref ImageView1D / @ref ImageView2D / + * @ref ImageView3D and @cpp char @ce for @ref MutableImageView1D / + * @ref MutableImageView2D / @ref MutableImageView3D. See also + * @ref ErasedType. + */ + typedef T Type; + + /** + * @brief Erased data type + * + * @cpp const void @ce for @ref ImageView1D / @ref ImageView2D / + * @ref ImageView3D and @cpp const void @ce for @ref MutableImageView1D + * / @ref MutableImageView2D / @ref MutableImageView3D. See also + * @ref Type. + */ + typedef typename std::conditional::value, const void, void>::type ErasedType; + enum: UnsignedInt { Dimensions = dimensions /**< Image dimension count */ }; @@ -132,7 +167,7 @@ template class ImageView { * The @p data array is expected to be of proper size for given * parameters. */ - 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) noexcept; /** * @brief Constructor @@ -140,10 +175,10 @@ template class ImageView { * @param size Image size * @param data Image data * - * Equivalent to calling @ref ImageView(PixelStorage, PixelFormat, const VectorTypeFor&, Containers::ArrayView) + * Equivalent to calling @ref ImageView(PixelStorage, PixelFormat, const VectorTypeFor&, Containers::ArrayView) * 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) noexcept: ImageView{{}, format, size, data} {} /** * @brief Construct an empty view @@ -175,7 +210,7 @@ template class ImageView { * @param size Image size * @param data Image data * - * Unlike with @ref ImageView(PixelStorage, PixelFormat, const VectorTypeFor&, Containers::ArrayView), + * Unlike with @ref ImageView(PixelStorage, PixelFormat, const VectorTypeFor&, Containers::ArrayView), * where pixel size is calculated automatically using * @ref pixelSize(PixelFormat), this allows you to specify an * implementation-specific pixel format and pixel size directly. Uses @@ -185,14 +220,14 @@ template class ImageView { * The @p data array is expected to be of proper size for given * parameters. */ - 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) 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) noexcept; /** * @brief Construct an empty view with implementation-specific pixel format @@ -230,10 +265,10 @@ template class ImageView { * @param data Image data * * Uses ADL to find a corresponding @cpp pixelSize(T, U) @ce overload, - * then calls @ref ImageView(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, Containers::ArrayView) + * then calls @ref ImageView(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, Containers::ArrayView) * with calculated pixel size. */ - template explicit ImageView(PixelStorage storage, T format, U formatExtra, const VectorTypeFor& size, Containers::ArrayView data) noexcept; + template explicit ImageView(PixelStorage storage, U format, V formatExtra, const VectorTypeFor& size, Containers::ArrayView data) noexcept; /** * @brief Construct an image view with implementation-specific pixel format @@ -243,10 +278,10 @@ template class ImageView { * @param data Image data * * Uses ADL to find a corresponding @cpp pixelSize(T) @ce overload, - * then calls @ref ImageView(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, Containers::ArrayView) + * then calls @ref ImageView(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, Containers::ArrayView) * with calculated pixel size and @p formatExtra set to @cpp 0 @ce. */ - template explicit ImageView(PixelStorage storage, T format, const VectorTypeFor& size, Containers::ArrayView data) noexcept; + template explicit ImageView(PixelStorage storage, U format, const VectorTypeFor& size, Containers::ArrayView data) noexcept; /** * @brief Construct an image view with implementation-specific pixel format @@ -255,10 +290,10 @@ template class ImageView { * @param size Image size * @param data Image data * - * Equivalent to calling @ref ImageView(PixelStorage, T, U, const VectorTypeFor&, Containers::ArrayView) + * Equivalent to calling @ref ImageView(PixelStorage, U, V, const VectorTypeFor&, Containers::ArrayView) * with default-constructed @ref PixelStorage. */ - template explicit ImageView(T format, U 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) noexcept: ImageView{{}, format, formatExtra, size, data} {} /** * @brief Construct an image view with implementation-specific pixel format @@ -266,10 +301,10 @@ template class ImageView { * @param size Image size * @param data Image data * - * Equivalent to calling @ref ImageView(PixelStorage, T, const VectorTypeFor&, Containers::ArrayView) + * Equivalent to calling @ref ImageView(PixelStorage, U, const VectorTypeFor&, Containers::ArrayView) * with default-constructed @ref PixelStorage. */ - template explicit ImageView(T format, const VectorTypeFor& size, Containers::ArrayView data) noexcept: ImageView{{}, format, size, data} {} + template explicit ImageView(U format, const VectorTypeFor& size, Containers::ArrayView data) noexcept: ImageView{{}, format, size, data} {} /** * @brief Construct an empty view with implementation-specific pixel format @@ -285,7 +320,7 @@ template class ImageView { * Data pointer is set to @cpp nullptr @ce, call @ref setData() to * assign a memory view to the image. */ - template explicit ImageView(PixelStorage storage, T format, U formatExtra, const VectorTypeFor& size) noexcept; + template explicit ImageView(PixelStorage storage, U format, V formatExtra, const VectorTypeFor& size) noexcept; /** * @brief Construct an empty view with implementation-specific pixel format @@ -300,7 +335,7 @@ template class ImageView { * Data pointer is set to @cpp nullptr @ce, call @ref setData() to * assign a memory view to the image. */ - template explicit ImageView(PixelStorage storage, T format, const VectorTypeFor& size) noexcept; + template explicit ImageView(PixelStorage storage, U format, const VectorTypeFor& size) noexcept; /** * @brief Construct an empty view with implementation-specific pixel format @@ -308,20 +343,23 @@ template class ImageView { * @param formatExtra Additional pixel format specifier * @param size Image size * - * Equivalent to calling @ref ImageView(PixelStorage, T, U, const VectorTypeFor&, Containers::ArrayView) + * Equivalent to calling @ref ImageView(PixelStorage, U, V, const VectorTypeFor&, Containers::ArrayView) * with default-constructed @ref PixelStorage. */ - template explicit ImageView(T format, U formatExtra, const VectorTypeFor& size) noexcept: ImageView{{}, format, formatExtra, size} {} + template explicit ImageView(U format, V formatExtra, const VectorTypeFor& size) noexcept: ImageView{{}, format, formatExtra, size} {} /** * @brief Construct an empty view with implementation-specific pixel format * @param format Format of pixel data * @param size Image size * - * Equivalent to calling @ref ImageView(PixelStorage, T, const VectorTypeFor&) + * Equivalent to calling @ref ImageView(PixelStorage, U, const VectorTypeFor&) * with default-constructed @ref PixelStorage. */ - template explicit ImageView(T format, const VectorTypeFor& size) noexcept: ImageView{{}, format, size} {} + template explicit ImageView(U format, const VectorTypeFor& size) noexcept: ImageView{{}, format, size} {} + + /** @brief Convert a mutable view to a const one */ + template::value &&!std::is_const::value>::type> /*implicit*/ ImageView(const ImageView& other) noexcept; /** @brief Storage of pixel data */ PixelStorage storage() const { return _storage; } @@ -371,7 +409,7 @@ template class ImageView { * * @see @ref pixels() */ - Containers::ArrayView data() const { return _data; } + Containers::ArrayView data() const { return _data; } #ifdef MAGNUM_BUILD_DEPRECATED /** @@ -380,8 +418,8 @@ template class ImageView { * @ref Corrade::Containers::arrayCast() instead for properly * bounds-checked type conversion. */ - template CORRADE_DEPRECATED("use data() together with Containers::arrayCast() instead") const T* data() const { - return reinterpret_cast(_data.data()); + template CORRADE_DEPRECATED("use data() together with Containers::arrayCast() instead") const U* data() const { + return reinterpret_cast(_data.data()); } #endif @@ -391,7 +429,7 @@ template class ImageView { * The data array is expected to be of proper size for parameters * specified in the constructor. */ - void setData(Containers::ArrayView data); + void setData(Containers::ArrayView data); /** * @brief View on pixel data @@ -399,7 +437,7 @@ template class ImageView { * Provides direct and easy-to-use access to image pixels. See * @ref Image-pixel-views for more information. */ - Containers::StridedArrayView pixels() const; + Containers::StridedArrayView pixels() const; /** * @brief View on pixel data with a concrete pixel type @@ -409,29 +447,65 @@ template class ImageView { * correct type for given @ref format() --- checking it on the library * side is not possible for the general case. */ - template Containers::StridedArrayView pixels() const { + template Containers::StridedArrayView::value, typename std::add_const::type, U>::type> pixels() const { /* Deliberately not adding a StridedArrayView include, it should work without since this is a templated function */ - return Containers::arrayCast(pixels()); + return Containers::arrayCast::value, typename std::add_const::type, U>::type>(pixels()); } private: + /* Needed for mutable->const conversion */ + template friend class ImageView; + PixelStorage _storage; PixelFormat _format; UnsignedInt _formatExtra; UnsignedInt _pixelSize; Math::Vector _size; - Containers::ArrayView _data; + Containers::ArrayView _data; }; -/** @brief One-dimensional image view */ -typedef ImageView<1> ImageView1D; +/** +@brief One-dimensional image view + +@see @ref MutableImageView1D, @ref CompressedImageView1D +*/ +typedef ImageView<1, const char> ImageView1D; + +/** +@brief Two-dimensional image view + +@see @ref MutableImageView2D, @ref CompressedImageView2D +*/ +typedef ImageView<2, const char> ImageView2D; + +/** +@brief Three-dimensional image view + +@see @ref MutableImageView3D, @ref CompressedImageView3D +*/ +typedef ImageView<3, const char> ImageView3D; + +/** +@brief One-dimensional mutable image view + +@see @ref ImageView1D, @ref MutableCompressedImageView1D +*/ +typedef ImageView<1, char> MutableImageView1D; -/** @brief Two-dimensional image view */ -typedef ImageView<2> ImageView2D; +/** +@brief Two-dimensional mutable image view -/** @brief Three-dimensional image view */ -typedef ImageView<3> ImageView3D; +@see @ref ImageView2D, @ref MutableCompressedImageView2D +*/ +typedef ImageView<2, char> MutableImageView2D; + +/** +@brief Three-dimensional mutable image view + +@see @ref ImageView3D, @ref MutableCompressedImageView3D +*/ +typedef ImageView<3, char> MutableImageView3D; /** @brief Compressed image view @@ -469,6 +543,16 @@ as first parameter. In the following snippet, the view is the bottom-right @snippet Magnum.cpp CompressedImageView-usage-storage +@section CompressedImageView-mutable Data mutability + +When using e.g. the @ref CompressedImageView2D typedef, the viewed data are +immutable. This is the most common use case, in order to be able to mutate the +underlying data (for example in order to read into a pre-allocated memory), use +@ref MutableCompressedImageView2D and friends instead. @ref CompressedImage and +@ref Trade::ImageData are convertible to either of those. Similarly to +@ref Corrade::Containers::ArrayView etc., a mutable view is also implicitly +convertible to a const one. + @subsection CompressedImageView-usage-implementation-specific Implementation-specific formats For known graphics APIs, there's a set of utility functions converting from @@ -494,10 +578,37 @@ extract the implementation-specific identifier using @snippet Magnum.cpp CompressedImageView-usage-gl-extract @see @ref CompressedImageView1D, @ref CompressedImageView2D, - @ref CompressedImageView3D + @ref CompressedImageView3D, @ref MutableCompressedImageView1D, + @ref MutableCompressedImageView2D, @ref MutableCompressedImageView3D */ -template class CompressedImageView { +template class CompressedImageView { public: + /* Pointer arithmetic relies on the type being a single byte */ + static_assert(std::is_same::value ||std::is_same::value, + "image view type can be either char or const char"); + + /** + * @brief Raw data type + * + * @cpp const char @ce for @ref CompressedImageView1D / + * @ref CompressedImageView2D / @ref CompressedImageView3D and + * @cpp char @ce for @ref MutableCompressedImageView1D / + * @ref MutableCompressedImageView2D / + * @ref MutableCompressedImageView3D. See also @ref ErasedType. + */ + typedef T Type; + + /** + * @brief Erased data type + * + * @cpp const void @ce for @ref CompressedImageView1D / + * @ref CompressedImageView2D / @ref CompressedImageView3D and + * @cpp const void @ce for @ref MutableCompressedImageView1D / + * @ref MutableCompressedImageView2D / @ref MutableCompressedImageView3D. + * See also @ref Type. + */ + typedef typename std::conditional::value, const void, void>::type ErasedType; + enum: UnsignedInt { Dimensions = dimensions /**< Image dimension count */ }; @@ -509,7 +620,7 @@ template class CompressedImageView { * @param size Image size * @param data Image data */ - 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) noexcept; /** * @brief Constructor @@ -517,10 +628,10 @@ template class CompressedImageView { * @param size Image size * @param data Image data * - * Equivalent to calling @ref CompressedImageView(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, Containers::ArrayView) + * Equivalent to calling @ref CompressedImageView(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, Containers::ArrayView) * 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) noexcept: CompressedImageView{{}, format, size, data} {} /** * @brief Construct an empty view @@ -553,7 +664,7 @@ template class CompressedImageView { * Uses @ref compressedPixelFormatWrap() internally to convert * @p format to @ref CompressedPixelFormat. */ - template explicit CompressedImageView(CompressedPixelStorage storage, T format, const VectorTypeFor& size, Containers::ArrayView data) noexcept; + template explicit CompressedImageView(CompressedPixelStorage storage, U format, const VectorTypeFor& size, Containers::ArrayView data) noexcept; /** * @brief Construct an image view with implementation-specific format @@ -561,10 +672,10 @@ template class CompressedImageView { * @param size Image size * @param data Image data * - * Equivalent to calling @ref CompressedImageView(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, Containers::ArrayView) + * Equivalent to calling @ref CompressedImageView(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, Containers::ArrayView) * with default-constructed @ref CompressedPixelStorage. */ - template explicit CompressedImageView(T format, const VectorTypeFor& size, Containers::ArrayView data) noexcept: CompressedImageView{{}, format, size, data} {} + template explicit CompressedImageView(U format, const VectorTypeFor& size, Containers::ArrayView data) noexcept: CompressedImageView{{}, format, size, data} {} /** * @brief Construct an empty view with implementation-specific format @@ -577,7 +688,7 @@ template class CompressedImageView { * @cpp nullptr @ce, call @ref setData() to assign a memory view to the * image. */ - template explicit CompressedImageView(CompressedPixelStorage storage, T format, const VectorTypeFor& size) noexcept; + template explicit CompressedImageView(CompressedPixelStorage storage, U format, const VectorTypeFor& size) noexcept; /** * @brief Construct an empty view with implementation-specific format @@ -587,7 +698,10 @@ template class CompressedImageView { * Equivalent to calling @ref CompressedImageView(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&) * with default-constructed @ref CompressedPixelStorage. */ - template explicit CompressedImageView(T format, const VectorTypeFor& size) noexcept: CompressedImageView{{}, format, size} {} + template explicit CompressedImageView(U format, const VectorTypeFor& size) noexcept: CompressedImageView{{}, format, size} {} + + /** @brief Convert a mutable view to a const one */ + template::value &&!std::is_const::value>::type> /*implicit*/ CompressedImageView(const CompressedImageView& other) noexcept; /** @brief Storage of compressed pixel data */ CompressedPixelStorage storage() const { return _storage; } @@ -617,7 +731,7 @@ template class CompressedImageView { } /** @brief Image data */ - Containers::ArrayView data() const { return _data; } + Containers::ArrayView data() const { return _data; } #ifdef MAGNUM_BUILD_DEPRECATED /** @@ -626,8 +740,8 @@ template class CompressedImageView { * @ref Corrade::Containers::arrayCast() instead for properly * bounds-checked type conversion. */ - template CORRADE_DEPRECATED("use data() together with Containers::arrayCast() instead") const T* data() const { - return reinterpret_cast(_data.data()); + template CORRADE_DEPRECATED("use data() together with Containers::arrayCast() instead") const U* data() const { + return reinterpret_cast(_data.data()); } #endif @@ -637,30 +751,66 @@ template class CompressedImageView { * The data array is expected to be of proper size for parameters * specified in the constructor. */ - void setData(Containers::ArrayView data) { - _data = {reinterpret_cast(data.data()), data.size()}; + void setData(Containers::ArrayView data) { + _data = {reinterpret_cast(data.data()), data.size()}; } private: + /* Needed for mutable->const conversion */ + template friend 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, Containers::ArrayView data) noexcept; explicit CompressedImageView(CompressedPixelStorage storage, UnsignedInt format, const VectorTypeFor& size) noexcept; CompressedPixelStorage _storage; CompressedPixelFormat _format; Math::Vector _size; - Containers::ArrayView _data; + Containers::ArrayView _data; }; -/** @brief One-dimensional compressed image view */ -typedef CompressedImageView<1> CompressedImageView1D; +/** +@brief One-dimensional compressed image view -/** @brief Two-dimensional compressed image view */ -typedef CompressedImageView<2> CompressedImageView2D; +@see @ref MutableCompressedImageView1D, @ref ImageView1D +*/ +typedef CompressedImageView<1, const char> CompressedImageView1D; -/** @brief Three-dimensional compressed image view */ -typedef CompressedImageView<3> CompressedImageView3D; +/** +@brief Two-dimensional compressed image view + +@see @ref MutableCompressedImageView2D, @ref ImageView2D +*/ +typedef CompressedImageView<2, const char> CompressedImageView2D; + +/** +@brief Three-dimensional compressed image view + +@see @ref MutableCompressedImageView3D, @ref ImageView3D +*/ +typedef CompressedImageView<3, const char> CompressedImageView3D; + +/** +@brief One-dimensional mutable compressed image view + +@see @ref CompressedImageView1D, @ref MutableImageView1D +*/ +typedef CompressedImageView<1, char> MutableCompressedImageView1D; + +/** +@brief Two-dimensional mutable compressed image view + +@see @ref CompressedImageView2D, @ref MutableImageView2D +*/ +typedef CompressedImageView<2, char> MutableCompressedImageView2D; + +/** +@brief Three-dimensional mutable compressed image view + +@see @ref CompressedImageView3D, @ref MutableImageView3D +*/ +typedef CompressedImageView<3, char> MutableCompressedImageView3D; namespace Implementation { template inline UnsignedInt pixelSizeAdl(T format) { @@ -672,36 +822,40 @@ namespace Implementation { } } -template template inline ImageView::ImageView(const PixelStorage storage, const T format, const U formatExtra, const VectorTypeFor& size, const Containers::ArrayView data) noexcept: ImageView{storage, UnsignedInt(format), UnsignedInt(formatExtra), Implementation::pixelSizeAdl(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) noexcept: ImageView{storage, UnsignedInt(format), UnsignedInt(formatExtra), Implementation::pixelSizeAdl(format, formatExtra), size, data} { 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 T format, const VectorTypeFor& size, const Containers::ArrayView data) noexcept: ImageView{storage, UnsignedInt(format), {}, Implementation::pixelSizeAdl(format), size, data} { - static_assert(sizeof(T) <= 4, +template template inline ImageView::ImageView(const PixelStorage storage, const U format, const VectorTypeFor& size, const Containers::ArrayView data) noexcept: ImageView{storage, UnsignedInt(format), {}, Implementation::pixelSizeAdl(format), size, data} { + static_assert(sizeof(U) <= 4, "format types larger than 32bits are not supported"); } -template template inline ImageView::ImageView(const PixelStorage storage, const T format, const U formatExtra, const VectorTypeFor& size) noexcept: ImageView{storage, UnsignedInt(format), UnsignedInt(formatExtra), Implementation::pixelSizeAdl(format, formatExtra), size} { - static_assert(sizeof(T) <= 4 && sizeof(U) <= 4, +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::pixelSizeAdl(format, formatExtra), size} { + 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 T format, const VectorTypeFor& size) noexcept: ImageView{storage, UnsignedInt(format), {}, Implementation::pixelSizeAdl(format), size} { - static_assert(sizeof(T) <= 4, +template template inline ImageView::ImageView(const PixelStorage storage, const U format, const VectorTypeFor& size) noexcept: ImageView{storage, UnsignedInt(format), {}, Implementation::pixelSizeAdl(format), size} { + static_assert(sizeof(U) <= 4, "format types larger than 32bits are not supported"); } -template template inline CompressedImageView::CompressedImageView(const CompressedPixelStorage storage, const T format, const VectorTypeFor& size, const Containers::ArrayView data) noexcept: CompressedImageView{storage, UnsignedInt(format), size, data} { - static_assert(sizeof(T) <= 4, +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 inline CompressedImageView::CompressedImageView(const CompressedPixelStorage storage, const U format, const VectorTypeFor& size, const Containers::ArrayView data) noexcept: CompressedImageView{storage, UnsignedInt(format), size, data} { + static_assert(sizeof(U) <= 4, "format types larger than 32bits are not supported"); } -template template inline CompressedImageView::CompressedImageView(const CompressedPixelStorage storage, const T format, const VectorTypeFor& size) noexcept: CompressedImageView{storage, UnsignedInt(format), size} { - static_assert(sizeof(T) <= 4, +template template inline CompressedImageView::CompressedImageView(const CompressedPixelStorage storage, const U format, const VectorTypeFor& size) noexcept: CompressedImageView{storage, UnsignedInt(format), size} { + static_assert(sizeof(U) <= 4, "format types larger than 32bits are not supported"); } +template template CompressedImageView::CompressedImageView(const CompressedImageView& other) noexcept: _storage{other._storage}, _format{other._format}, _size{other._size}, _data{other._data} {} + } #endif diff --git a/src/Magnum/Magnum.h b/src/Magnum/Magnum.h index 5da25fb37..aabca4cdb 100644 --- a/src/Magnum/Magnum.h +++ b/src/Magnum/Magnum.h @@ -727,15 +727,21 @@ typedef CompressedImage<1> CompressedImage1D; typedef CompressedImage<2> CompressedImage2D; typedef CompressedImage<3> CompressedImage3D; -template class ImageView; -typedef ImageView<1> ImageView1D; -typedef ImageView<2> ImageView2D; -typedef ImageView<3> ImageView3D; - -template class CompressedImageView; -typedef CompressedImageView<1> CompressedImageView1D; -typedef CompressedImageView<2> CompressedImageView2D; -typedef CompressedImageView<3> CompressedImageView3D; +template class ImageView; +typedef ImageView<1, const char> ImageView1D; +typedef ImageView<2, const char> ImageView2D; +typedef ImageView<3, const char> ImageView3D; +typedef ImageView<1, char> MutableImageView1D; +typedef ImageView<2, char> MutableImageView2D; +typedef ImageView<3, char> MutableImageView3D; + +template class CompressedImageView; +typedef CompressedImageView<1, const char> CompressedImageView1D; +typedef CompressedImageView<2, const char> CompressedImageView2D; +typedef CompressedImageView<3, const char> CompressedImageView3D; +typedef CompressedImageView<1, char> MutableCompressedImageView1D; +typedef CompressedImageView<2, char> MutableCompressedImageView2D; +typedef CompressedImageView<3, char> MutableCompressedImageView3D; enum class MeshPrimitive: UnsignedInt; enum class MeshIndexType: UnsignedInt; diff --git a/src/Magnum/Test/ImageTest.cpp b/src/Magnum/Test/ImageTest.cpp index 769350ecf..52b4dd0d6 100644 --- a/src/Magnum/Test/ImageTest.cpp +++ b/src/Magnum/Test/ImageTest.cpp @@ -56,10 +56,10 @@ struct ImageTest: TestSuite::Tester { void constructMoveCompressedGeneric(); void constructMoveCompressedImplementationSpecific(); - void toViewGeneric(); - void toViewImplementationSpecific(); - void toViewCompressedGeneric(); - void toViewCompressedImplementationSpecific(); + template void toViewGeneric(); + template void toViewImplementationSpecific(); + template void toViewCompressedGeneric(); + template void toViewCompressedImplementationSpecific(); void data(); void dataCompressed(); @@ -77,6 +77,20 @@ struct ImageTest: TestSuite::Tester { void pixels3D(); }; +template struct MutabilityTraits; +template<> struct MutabilityTraits { + typedef const Image2D ImageType; + typedef const CompressedImage2D CompressedImageType; + + static const char* name() { return "ImageView"; } +}; +template<> struct MutabilityTraits { + typedef Image2D ImageType; + typedef CompressedImage2D CompressedImageType; + + static const char* name() { return "MutableImageView"; } +}; + ImageTest::ImageTest() { addTests({&ImageTest::constructGeneric, &ImageTest::constructGenericPlaceholder, @@ -97,10 +111,14 @@ ImageTest::ImageTest() { &ImageTest::constructMoveCompressedGeneric, &ImageTest::constructMoveCompressedImplementationSpecific, - &ImageTest::toViewGeneric, - &ImageTest::toViewImplementationSpecific, - &ImageTest::toViewCompressedGeneric, - &ImageTest::toViewCompressedImplementationSpecific, + &ImageTest::toViewGeneric, + &ImageTest::toViewGeneric, + &ImageTest::toViewImplementationSpecific, + &ImageTest::toViewImplementationSpecific, + &ImageTest::toViewCompressedGeneric, + &ImageTest::toViewCompressedGeneric, + &ImageTest::toViewCompressedImplementationSpecific, + &ImageTest::toViewCompressedImplementationSpecific, &ImageTest::data, &ImageTest::dataCompressed, @@ -556,11 +574,13 @@ void ImageTest::constructMoveCompressedImplementationSpecific() { CORRADE_COMPARE(c.data().size(), 8); } -void ImageTest::toViewGeneric() { +template void ImageTest::toViewGeneric() { + setTestCaseTemplateName(MutabilityTraits::name()); + auto data = new char[3*4]; - const Image2D a{PixelStorage{}.setAlignment(1), + typename MutabilityTraits::ImageType a{PixelStorage{}.setAlignment(1), PixelFormat::RG16I, {1, 3}, Containers::Array{data, 3*4}}; - ImageView2D b = a; + ImageView<2, T> b = a; CORRADE_COMPARE(b.storage().alignment(), 1); CORRADE_COMPARE(b.format(), PixelFormat::RG16I); @@ -570,11 +590,13 @@ void ImageTest::toViewGeneric() { CORRADE_COMPARE(b.data(), data); } -void ImageTest::toViewImplementationSpecific() { +template void ImageTest::toViewImplementationSpecific() { + setTestCaseTemplateName(MutabilityTraits::name()); + auto data = new char[3*6]; - const Image2D a{PixelStorage{}.setAlignment(1), + typename MutabilityTraits::ImageType a{PixelStorage{}.setAlignment(1), GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, Containers::Array{data, 3*6}}; - ImageView2D b = a; + ImageView<2, T> b = a; CORRADE_COMPARE(b.storage().alignment(), 1); CORRADE_COMPARE(b.format(), pixelFormatWrap(GL::PixelFormat::RGB)); @@ -584,12 +606,14 @@ void ImageTest::toViewImplementationSpecific() { CORRADE_COMPARE(b.data(), data); } -void ImageTest::toViewCompressedGeneric() { +template void ImageTest::toViewCompressedGeneric() { + setTestCaseTemplateName(MutabilityTraits::name()); + auto data = new char[8]; - const CompressedImage2D a{ + typename MutabilityTraits::CompressedImageType a{ CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), CompressedPixelFormat::Bc1RGBUnorm, {4, 4}, Containers::Array{data, 8}}; - CompressedImageView2D b = a; + CompressedImageView<2, T> b = a; CORRADE_COMPARE(b.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(b.format(), CompressedPixelFormat::Bc1RGBUnorm); @@ -598,12 +622,14 @@ void ImageTest::toViewCompressedGeneric() { CORRADE_COMPARE(b.data().size(), 8); } -void ImageTest::toViewCompressedImplementationSpecific() { +template void ImageTest::toViewCompressedImplementationSpecific() { + setTestCaseTemplateName(MutabilityTraits::name()); + auto data = new char[8]; - const CompressedImage2D a{ + typename MutabilityTraits::CompressedImageType a{ CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 4}, Containers::Array{data, 8}}; - CompressedImageView2D b = a; + CompressedImageView<2, T> b = a; CORRADE_COMPARE(b.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(b.format(), compressedPixelFormatWrap(GL::CompressedPixelFormat::RGBS3tcDxt1)); diff --git a/src/Magnum/Test/ImageViewTest.cpp b/src/Magnum/Test/ImageViewTest.cpp index 62d83a4fa..827a13fcc 100644 --- a/src/Magnum/Test/ImageViewTest.cpp +++ b/src/Magnum/Test/ImageViewTest.cpp @@ -37,16 +37,19 @@ namespace Magnum { namespace Test { namespace { struct ImageViewTest: TestSuite::Tester { explicit ImageViewTest(); - void constructGeneric(); - void constructGenericEmpty(); - void constructGenericEmptyNullptr(); - void constructImplementationSpecific(); - void constructImplementationSpecificEmpty(); - void constructImplementationSpecificEmptyNullptr(); - void constructCompressedGeneric(); - void constructCompressedGenericEmpty(); - void constructCompressedImplementationSpecific(); - void constructCompressedImplementationSpecificEmpty(); + template void constructGeneric(); + template void constructGenericEmpty(); + template void constructGenericEmptyNullptr(); + template void constructImplementationSpecific(); + template void constructImplementationSpecificEmpty(); + template void constructImplementationSpecificEmptyNullptr(); + template void constructCompressedGeneric(); + template void constructCompressedGenericEmpty(); + template void constructCompressedImplementationSpecific(); + template void constructCompressedImplementationSpecificEmpty(); + + void constructFromMutable(); + void constructCompressedFromMutable(); void constructInvalidSize(); void constructCompressedInvalidSize(); @@ -54,28 +57,49 @@ struct ImageViewTest: TestSuite::Tester { void dataProperties(); void dataPropertiesCompressed(); - void setData(); - void setDataCompressed(); + template void setData(); + template void setDataCompressed(); void setDataInvalidSize(); void setDataCompressedInvalidSize(); - void pixels1D(); - void pixels2D(); - void pixels3D(); + template void pixels1D(); + template void pixels2D(); + template void pixels3D(); +}; + +template struct MutabilityTraits; +template<> struct MutabilityTraits { + static const char* name() { return "ImageView"; } +}; +template<> struct MutabilityTraits { + static const char* name() { return "MutableImageView"; } }; ImageViewTest::ImageViewTest() { - addTests({&ImageViewTest::constructGeneric, - &ImageViewTest::constructGenericEmpty, - &ImageViewTest::constructGenericEmptyNullptr, - &ImageViewTest::constructImplementationSpecific, - &ImageViewTest::constructImplementationSpecificEmpty, - &ImageViewTest::constructImplementationSpecificEmptyNullptr, - &ImageViewTest::constructCompressedGeneric, - &ImageViewTest::constructCompressedGenericEmpty, - &ImageViewTest::constructCompressedImplementationSpecific, - &ImageViewTest::constructCompressedImplementationSpecificEmpty, + addTests({&ImageViewTest::constructGeneric, + &ImageViewTest::constructGeneric, + &ImageViewTest::constructGenericEmpty, + &ImageViewTest::constructGenericEmpty, + &ImageViewTest::constructGenericEmptyNullptr, + &ImageViewTest::constructGenericEmptyNullptr, + &ImageViewTest::constructImplementationSpecific, + &ImageViewTest::constructImplementationSpecific, + &ImageViewTest::constructImplementationSpecificEmpty, + &ImageViewTest::constructImplementationSpecificEmpty, + &ImageViewTest::constructImplementationSpecificEmptyNullptr, + &ImageViewTest::constructImplementationSpecificEmptyNullptr, + &ImageViewTest::constructCompressedGeneric, + &ImageViewTest::constructCompressedGeneric, + &ImageViewTest::constructCompressedGenericEmpty, + &ImageViewTest::constructCompressedGenericEmpty, + &ImageViewTest::constructCompressedImplementationSpecific, + &ImageViewTest::constructCompressedImplementationSpecific, + &ImageViewTest::constructCompressedImplementationSpecificEmpty, + &ImageViewTest::constructCompressedImplementationSpecificEmpty, + + &ImageViewTest::constructFromMutable, + &ImageViewTest::constructCompressedFromMutable, &ImageViewTest::constructInvalidSize, &ImageViewTest::constructCompressedInvalidSize, @@ -83,15 +107,20 @@ ImageViewTest::ImageViewTest() { &ImageViewTest::dataProperties, &ImageViewTest::dataPropertiesCompressed, - &ImageViewTest::setData, - &ImageViewTest::setDataCompressed, + &ImageViewTest::setData, + &ImageViewTest::setData, + &ImageViewTest::setDataCompressed, + &ImageViewTest::setDataCompressed, &ImageViewTest::setDataInvalidSize, &ImageViewTest::setDataCompressedInvalidSize, - &ImageViewTest::pixels1D, - &ImageViewTest::pixels2D, - &ImageViewTest::pixels3D}); + &ImageViewTest::pixels1D, + &ImageViewTest::pixels1D, + &ImageViewTest::pixels2D, + &ImageViewTest::pixels2D, + &ImageViewTest::pixels3D, + &ImageViewTest::pixels3D}); } namespace GL { @@ -122,21 +151,23 @@ namespace Vk { enum class CompressedPixelFormat { Bc1SRGBAlpha = 42 }; } -void ImageViewTest::constructGeneric() { +template void ImageViewTest::constructGeneric() { + setTestCaseTemplateName(MutabilityTraits::name()); + { - const char data[4*4]{}; - ImageView2D a{PixelFormat::RGBA8Unorm, {1, 3}, data}; + T data[4*4]{}; + ImageView<2, T> a{PixelFormat::RGBA8Unorm, {1, 3}, data}; CORRADE_COMPARE(a.storage().alignment(), 4); CORRADE_COMPARE(a.format(), PixelFormat::RGBA8Unorm); CORRADE_COMPARE(a.formatExtra(), 0); CORRADE_COMPARE(a.pixelSize(), 4); CORRADE_COMPARE(a.size(), (Vector2i{1, 3})); - CORRADE_COMPARE(a.data(), data); + CORRADE_COMPARE(a.data(), &data[0]); CORRADE_COMPARE(a.data().size(), 4*4); } { - const char data[3*2]{}; - ImageView2D a{PixelStorage{}.setAlignment(1), + T data[3*2]{}; + ImageView<2, T> a{PixelStorage{}.setAlignment(1), PixelFormat::R16UI, {1, 3}, data}; CORRADE_COMPARE(a.storage().alignment(), 1); @@ -144,14 +175,16 @@ void ImageViewTest::constructGeneric() { CORRADE_COMPARE(a.formatExtra(), 0); CORRADE_COMPARE(a.pixelSize(), 2); CORRADE_COMPARE(a.size(), (Vector2i{1, 3})); - CORRADE_COMPARE(a.data(), data); + CORRADE_COMPARE(a.data(), &data[0]); CORRADE_COMPARE(a.data().size(), 3*2); } } -void ImageViewTest::constructGenericEmpty() { +template void ImageViewTest::constructGenericEmpty() { + setTestCaseTemplateName(MutabilityTraits::name()); + { - ImageView2D a{PixelFormat::RG32F, {2, 6}}; + ImageView<2, T> a{PixelFormat::RG32F, {2, 6}}; CORRADE_COMPARE(a.storage().alignment(), 4); CORRADE_COMPARE(a.format(), PixelFormat::RG32F); @@ -160,7 +193,7 @@ void ImageViewTest::constructGenericEmpty() { CORRADE_COMPARE(a.size(), (Vector2i{2, 6})); CORRADE_COMPARE(a.data(), nullptr); } { - ImageView2D a{PixelStorage{}.setAlignment(1), + ImageView<2, T> a{PixelStorage{}.setAlignment(1), PixelFormat::RGB16F, {8, 3}}; CORRADE_COMPARE(a.storage().alignment(), 1); @@ -172,12 +205,14 @@ void ImageViewTest::constructGenericEmpty() { } } -void ImageViewTest::constructGenericEmptyNullptr() { +template void ImageViewTest::constructGenericEmptyNullptr() { + setTestCaseTemplateName(MutabilityTraits::name()); + /* This should be deprecated/removed, as it doesn't provide anything over the above and can lead to silent errors */ { - ImageView2D a{PixelFormat::RG32F, {2, 6}, nullptr}; + ImageView<2, T> a{PixelFormat::RG32F, {2, 6}, nullptr}; CORRADE_COMPARE(a.storage().alignment(), 4); CORRADE_COMPARE(a.format(), PixelFormat::RG32F); @@ -186,7 +221,7 @@ void ImageViewTest::constructGenericEmptyNullptr() { CORRADE_COMPARE(a.size(), (Vector2i{2, 6})); CORRADE_COMPARE(a.data(), nullptr); } { - ImageView2D a{PixelStorage{}.setAlignment(1), + ImageView<2, T> a{PixelStorage{}.setAlignment(1), PixelFormat::RGB16F, {8, 3}, nullptr}; CORRADE_COMPARE(a.storage().alignment(), 1); @@ -198,22 +233,24 @@ void ImageViewTest::constructGenericEmptyNullptr() { } } -void ImageViewTest::constructImplementationSpecific() { +template void ImageViewTest::constructImplementationSpecific() { + setTestCaseTemplateName(MutabilityTraits::name()); + /* Single format */ { - const char data[3*12]{}; - ImageView2D a{Vk::PixelFormat::R32G32B32F, {1, 3}, data}; + T data[3*12]{}; + ImageView<2, T> a{Vk::PixelFormat::R32G32B32F, {1, 3}, data}; CORRADE_COMPARE(a.storage().alignment(), 4); CORRADE_COMPARE(a.format(), pixelFormatWrap(Vk::PixelFormat::R32G32B32F)); CORRADE_COMPARE(a.formatExtra(), 0); CORRADE_COMPARE(a.pixelSize(), 12); CORRADE_COMPARE(a.size(), (Vector2i{1, 3})); - CORRADE_COMPARE(a.data(), data); + CORRADE_COMPARE(a.data(), &data[0]); CORRADE_COMPARE(a.data().size(), 3*12); } { - const char data[3*12]{}; - ImageView2D a{PixelStorage{}.setAlignment(1), + T data[3*12]{}; + ImageView<2, T> a{PixelStorage{}.setAlignment(1), Vk::PixelFormat::R32G32B32F, {1, 3}, data}; CORRADE_COMPARE(a.storage().alignment(), 1); @@ -221,54 +258,56 @@ void ImageViewTest::constructImplementationSpecific() { CORRADE_COMPARE(a.formatExtra(), 0); CORRADE_COMPARE(a.pixelSize(), 12); CORRADE_COMPARE(a.size(), (Vector2i{1, 3})); - CORRADE_COMPARE(a.data(), data); + CORRADE_COMPARE(a.data(), &data[0]); CORRADE_COMPARE(a.data().size(), 3*12); } /* Format + extra */ { - const char data[3*8]{}; - ImageView2D a{GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, data}; + T data[3*8]{}; + ImageView<2, T> a{GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, data}; CORRADE_COMPARE(a.storage().alignment(), 4); CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(a.formatExtra(), UnsignedInt(GL::PixelType::UnsignedShort)); CORRADE_COMPARE(a.pixelSize(), 6); CORRADE_COMPARE(a.size(), Vector2i(1, 3)); - CORRADE_COMPARE(a.data(), data); + CORRADE_COMPARE(a.data(), &data[0]); CORRADE_COMPARE(a.data().size(), 3*8); } { - const char data[3*6]{}; - ImageView2D a{PixelStorage{}.setAlignment(1), + T data[3*6]{}; + ImageView<2, T> a{PixelStorage{}.setAlignment(1), GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, data}; CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(a.formatExtra(), UnsignedInt(GL::PixelType::UnsignedShort)); CORRADE_COMPARE(a.pixelSize(), 6); CORRADE_COMPARE(a.size(), Vector2i(1, 3)); - CORRADE_COMPARE(a.data(), data); + CORRADE_COMPARE(a.data(), &data[0]); CORRADE_COMPARE(a.data().size(), 3*6); } /* Manual pixel size */ { - const char data[3*6]{}; - ImageView2D a{PixelStorage{}.setAlignment(1), 666, 1337, 6, {1, 3}, data}; + T data[3*6]{}; + ImageView<2, T> a{PixelStorage{}.setAlignment(1), 666, 1337, 6, {1, 3}, data}; CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); CORRADE_COMPARE(a.formatExtra(), UnsignedInt(GL::PixelType::UnsignedShort)); CORRADE_COMPARE(a.pixelSize(), 6); CORRADE_COMPARE(a.size(), Vector2i(1, 3)); - CORRADE_COMPARE(a.data(), data); + CORRADE_COMPARE(a.data(), &data[0]); CORRADE_COMPARE(a.data().size(), 3*6); } } -void ImageViewTest::constructImplementationSpecificEmpty() { +template void ImageViewTest::constructImplementationSpecificEmpty() { + setTestCaseTemplateName(MutabilityTraits::name()); + /* Single format */ { - ImageView2D a{Vk::PixelFormat::R32G32B32F, {2, 16}}; + ImageView<2, T> a{Vk::PixelFormat::R32G32B32F, {2, 16}}; CORRADE_COMPARE(a.storage().alignment(), 4); CORRADE_COMPARE(a.format(), pixelFormatWrap(Vk::PixelFormat::R32G32B32F)); @@ -277,7 +316,7 @@ void ImageViewTest::constructImplementationSpecificEmpty() { CORRADE_COMPARE(a.size(), (Vector2i{2, 16})); CORRADE_COMPARE(a.data(), nullptr); } { - ImageView2D a{PixelStorage{}.setAlignment(1), + ImageView<2, T> a{PixelStorage{}.setAlignment(1), Vk::PixelFormat::R32G32B32F, {1, 2}}; CORRADE_COMPARE(a.storage().alignment(), 1); @@ -290,7 +329,7 @@ void ImageViewTest::constructImplementationSpecificEmpty() { /* Format + extra */ { - ImageView2D a{GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}}; + ImageView<2, T> a{GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}}; CORRADE_COMPARE(a.storage().alignment(), 4); CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); @@ -299,7 +338,7 @@ void ImageViewTest::constructImplementationSpecificEmpty() { CORRADE_COMPARE(a.size(), (Vector2i{1, 3})); CORRADE_COMPARE(a.data(), nullptr); } { - ImageView2D a{PixelStorage{}.setAlignment(1), + ImageView<2, T> a{PixelStorage{}.setAlignment(1), GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {8, 2}}; CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); @@ -311,7 +350,7 @@ void ImageViewTest::constructImplementationSpecificEmpty() { /* Manual pixel size */ { - ImageView2D a{PixelStorage{}.setAlignment(1), 666, 1337, 6, {3, 3}}; + ImageView<2, T> a{PixelStorage{}.setAlignment(1), 666, 1337, 6, {3, 3}}; CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); @@ -322,13 +361,15 @@ void ImageViewTest::constructImplementationSpecificEmpty() { } } -void ImageViewTest::constructImplementationSpecificEmptyNullptr() { +template void ImageViewTest::constructImplementationSpecificEmptyNullptr() { + setTestCaseTemplateName(MutabilityTraits::name()); + /* This should be deprecated/removed, as it doesn't provide anything over the above and can lead to silent errors */ /* Single format */ { - ImageView2D a{Vk::PixelFormat::R32G32B32F, {2, 16}, nullptr}; + ImageView<2, T> a{Vk::PixelFormat::R32G32B32F, {2, 16}, nullptr}; CORRADE_COMPARE(a.storage().alignment(), 4); CORRADE_COMPARE(a.format(), pixelFormatWrap(Vk::PixelFormat::R32G32B32F)); @@ -337,7 +378,7 @@ void ImageViewTest::constructImplementationSpecificEmptyNullptr() { CORRADE_COMPARE(a.size(), (Vector2i{2, 16})); CORRADE_COMPARE(a.data(), nullptr); } { - ImageView2D a{PixelStorage{}.setAlignment(1), + ImageView<2, T> a{PixelStorage{}.setAlignment(1), Vk::PixelFormat::R32G32B32F, {1, 2}, nullptr}; CORRADE_COMPARE(a.storage().alignment(), 1); @@ -350,7 +391,7 @@ void ImageViewTest::constructImplementationSpecificEmptyNullptr() { /* Format + extra */ { - ImageView2D a{GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, nullptr}; + ImageView<2, T> a{GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, nullptr}; CORRADE_COMPARE(a.storage().alignment(), 4); CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); @@ -359,7 +400,7 @@ void ImageViewTest::constructImplementationSpecificEmptyNullptr() { CORRADE_COMPARE(a.size(), (Vector2i{1, 3})); CORRADE_COMPARE(a.data(), nullptr); } { - ImageView2D a{PixelStorage{}.setAlignment(1), + ImageView<2, T> a{PixelStorage{}.setAlignment(1), GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {8, 2}, nullptr}; CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); @@ -371,7 +412,7 @@ void ImageViewTest::constructImplementationSpecificEmptyNullptr() { /* Manual pixel size */ { - ImageView2D a{PixelStorage{}.setAlignment(1), 666, 1337, 6, {3, 3}, nullptr}; + ImageView<2, T> a{PixelStorage{}.setAlignment(1), 666, 1337, 6, {3, 3}, nullptr}; CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); @@ -382,40 +423,44 @@ void ImageViewTest::constructImplementationSpecificEmptyNullptr() { } } -void ImageViewTest::constructCompressedGeneric() { +template void ImageViewTest::constructCompressedGeneric() { + setTestCaseTemplateName(MutabilityTraits::name()); + { - const char data[8]{}; - CompressedImageView2D a{CompressedPixelFormat::Bc1RGBAUnorm, {4, 4}, data}; + T data[8]{}; + CompressedImageView<2, T> a{CompressedPixelFormat::Bc1RGBAUnorm, {4, 4}, data}; CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{0}); CORRADE_COMPARE(a.format(), CompressedPixelFormat::Bc1RGBAUnorm); CORRADE_COMPARE(a.size(), (Vector2i{4, 4})); - CORRADE_COMPARE(a.data(), data); + CORRADE_COMPARE(a.data(), &data[0]); CORRADE_COMPARE(a.data().size(), 8); } { - const char data[8]{}; - CompressedImageView2D a{CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), + T data[8]{}; + CompressedImageView<2, T> a{CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), CompressedPixelFormat::Bc1RGBAUnorm, {4, 4}, data}; CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(a.format(), CompressedPixelFormat::Bc1RGBAUnorm); CORRADE_COMPARE(a.size(), (Vector2i{4, 4})); - CORRADE_COMPARE(a.data(), data); + CORRADE_COMPARE(a.data(), &data[0]); CORRADE_COMPARE(a.data().size(), 8); } } -void ImageViewTest::constructCompressedGenericEmpty() { +template void ImageViewTest::constructCompressedGenericEmpty() { + setTestCaseTemplateName(MutabilityTraits::name()); + { - CompressedImageView2D a{CompressedPixelFormat::Bc1RGBAUnorm, {8, 16}}; + CompressedImageView<2, T> a{CompressedPixelFormat::Bc1RGBAUnorm, {8, 16}}; CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{0}); CORRADE_COMPARE(a.format(), CompressedPixelFormat::Bc1RGBAUnorm); CORRADE_COMPARE(a.size(), (Vector2i{8, 16})); CORRADE_COMPARE(a.data(), nullptr); } { - CompressedImageView2D a{CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), + CompressedImageView<2, T> a{CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), CompressedPixelFormat::Bc1RGBAUnorm, {8, 16}}; CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{4}); @@ -425,44 +470,48 @@ void ImageViewTest::constructCompressedGenericEmpty() { } } -void ImageViewTest::constructCompressedImplementationSpecific() { +template void ImageViewTest::constructCompressedImplementationSpecific() { + setTestCaseTemplateName(MutabilityTraits::name()); + /* Format with autodetection */ { - const char data[8]{}; - CompressedImageView2D a{GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 4}, + T data[8]{}; + CompressedImageView<2, T> a{GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 4}, data}; CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{0}); CORRADE_COMPARE(a.format(), compressedPixelFormatWrap(GL::CompressedPixelFormat::RGBS3tcDxt1)); CORRADE_COMPARE(a.size(), (Vector2i{4, 4})); - CORRADE_COMPARE(a.data(), data); + CORRADE_COMPARE(a.data(), &data[0]); CORRADE_COMPARE(a.data().size(), 8); } { - const char data[8]{}; - CompressedImageView2D a{CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), + T data[8]{}; + CompressedImageView<2, T> a{CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 4}, data}; CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(a.format(), compressedPixelFormatWrap(GL::CompressedPixelFormat::RGBS3tcDxt1)); CORRADE_COMPARE(a.size(), (Vector2i{4, 4})); - CORRADE_COMPARE(a.data(), data); + CORRADE_COMPARE(a.data(), &data[0]); CORRADE_COMPARE(a.data().size(), 8); } /* Manual properties not implemented yet */ } -void ImageViewTest::constructCompressedImplementationSpecificEmpty() { +template void ImageViewTest::constructCompressedImplementationSpecificEmpty() { + setTestCaseTemplateName(MutabilityTraits::name()); + /* Format with autodetection */ { - CompressedImageView2D a{GL::CompressedPixelFormat::RGBS3tcDxt1, {8, 16}}; + CompressedImageView<2, T> a{GL::CompressedPixelFormat::RGBS3tcDxt1, {8, 16}}; 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(), nullptr); } { - CompressedImageView2D a{CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), + CompressedImageView<2, T> a{CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 8}}; CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{4}); @@ -474,6 +523,49 @@ void ImageViewTest::constructCompressedImplementationSpecificEmpty() { /* Manual properties not implemented yet */ } +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}; + CORRADE_COMPARE(a.storage().alignment(), 1); + CORRADE_COMPARE(a.format(), pixelFormatWrap(GL::PixelFormat::RGB)); + CORRADE_COMPARE(a.formatExtra(), UnsignedInt(GL::PixelType::UnsignedShort)); + CORRADE_COMPARE(a.pixelSize(), 6); + CORRADE_COMPARE(a.size(), Vector2i(1, 3)); + CORRADE_COMPARE(a.data(), &data[0]); + CORRADE_COMPARE(a.data().size(), 3*6); + + ImageView2D b = a; + CORRADE_COMPARE(b.storage().alignment(), 1); + CORRADE_COMPARE(b.format(), pixelFormatWrap(GL::PixelFormat::RGB)); + CORRADE_COMPARE(b.formatExtra(), UnsignedInt(GL::PixelType::UnsignedShort)); + CORRADE_COMPARE(b.pixelSize(), 6); + CORRADE_COMPARE(b.size(), Vector2i(1, 3)); + CORRADE_COMPARE(b.data(), &data[0]); + CORRADE_COMPARE(b.data().size(), 3*6); +} + +void ImageViewTest::constructCompressedFromMutable() { + /* Copied from constructCompressedImplementationSpecific(), as that exposes + most fields */ + char data[8]{}; + MutableCompressedImageView2D a{CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), + GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 4}, data}; + CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{4}); + CORRADE_COMPARE(a.format(), compressedPixelFormatWrap(GL::CompressedPixelFormat::RGBS3tcDxt1)); + CORRADE_COMPARE(a.size(), (Vector2i{4, 4})); + CORRADE_COMPARE(a.data(), &data[0]); + CORRADE_COMPARE(a.data().size(), 8); + + CompressedImageView2D b = a; + CORRADE_COMPARE(b.storage().compressedBlockSize(), Vector3i{4}); + CORRADE_COMPARE(b.format(), compressedPixelFormatWrap(GL::CompressedPixelFormat::RGBS3tcDxt1)); + CORRADE_COMPARE(b.size(), (Vector2i{4, 4})); + CORRADE_COMPARE(b.data(), &data[0]); + CORRADE_COMPARE(b.data().size(), 8); +} + void ImageViewTest::constructInvalidSize() { std::ostringstream out; Error redirectError{&out}; @@ -531,31 +623,35 @@ void ImageViewTest::dataPropertiesCompressed() { (std::pair, Math::Vector3>{{2*16, 2*16, 9*16}, {1, 3, 3}})); } -void ImageViewTest::setData() { - const char data[3*3]{}; - ImageView2D a{PixelStorage{}.setAlignment(1), +template void ImageViewTest::setData() { + setTestCaseTemplateName(MutabilityTraits::name()); + + T data[3*3]{}; + ImageView<2, T> a{PixelStorage{}.setAlignment(1), PixelFormat::RGB8Snorm, {1, 3}, data}; - const char data2[3*3]{}; + T data2[3*3]{}; a.setData(data2); CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), PixelFormat::RGB8Snorm); CORRADE_COMPARE(a.size(), Vector2i(1, 3)); - CORRADE_COMPARE(a.data(), data2); + CORRADE_COMPARE(a.data(), &data2[0]); } -void ImageViewTest::setDataCompressed() { - const char data[8]{}; - CompressedImageView2D a{ +template void ImageViewTest::setDataCompressed() { + setTestCaseTemplateName(MutabilityTraits::name()); + + T data[8]{}; + CompressedImageView<2, T> a{ CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), CompressedPixelFormat::Bc1RGBAUnorm, {4, 4}, data}; - const char data2[16]{}; + T data2[16]{}; a.setData(data2); CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(a.format(), CompressedPixelFormat::Bc1RGBAUnorm); CORRADE_COMPARE(a.size(), Vector2i(4, 4)); - CORRADE_COMPARE(a.data(), data2); + CORRADE_COMPARE(a.data(), &data2[0]); } void ImageViewTest::setDataInvalidSize() { @@ -591,8 +687,10 @@ void ImageViewTest::setDataCompressedInvalidSize() { } } -void ImageViewTest::pixels1D() { - ImageView1D image{ +template void ImageViewTest::pixels1D() { + setTestCaseTemplateName(MutabilityTraits::name()); + + ImageView<1, T> image{ PixelStorage{} .setAlignment(1) /** @todo alignment 4 expects 17 bytes. what */ .setSkip({3, 0, 0}), @@ -601,14 +699,18 @@ void ImageViewTest::pixels1D() { /* Full test is in ImageTest, this is just a sanity check */ - Containers::StridedArrayView1D pixels = image.pixels(); + auto pixels = image.template pixels(); + CORRADE_COMPARE(decltype(pixels)::Dimensions, 1); + CORRADE_COMPARE(std::is_const::value, std::is_const::value); CORRADE_COMPARE(pixels.size(), 2); CORRADE_COMPARE(pixels.stride(), 3); CORRADE_COMPARE(pixels.data(), image.data() + 3*3); } -void ImageViewTest::pixels2D() { - ImageView2D image{ +template void ImageViewTest::pixels2D() { + setTestCaseTemplateName(MutabilityTraits::name()); + + ImageView<2, T> image{ PixelStorage{} .setAlignment(4) .setSkip({3, 2, 0}) @@ -618,14 +720,18 @@ void ImageViewTest::pixels2D() { /* Full test is in ImageTest, this is just a sanity check */ - Containers::StridedArrayView2D pixels = image.pixels(); + auto pixels = image.template pixels(); + CORRADE_COMPARE(decltype(pixels)::Dimensions, 2); + CORRADE_COMPARE(std::is_const::value, std::is_const::value); CORRADE_COMPARE(pixels.size(), (Containers::StridedArrayView2D::Size{4, 2})); CORRADE_COMPARE(pixels.stride(), (Containers::StridedArrayView2D::Stride{20, 3})); CORRADE_COMPARE(pixels.data(), image.data() + 2*20 + 3*3); } -void ImageViewTest::pixels3D() { - ImageView3D image{ +template void ImageViewTest::pixels3D() { + setTestCaseTemplateName(MutabilityTraits::name()); + + ImageView<3, T> image{ PixelStorage{} .setAlignment(4) .setSkip({3, 2, 1}) @@ -636,7 +742,9 @@ void ImageViewTest::pixels3D() { /* Full test is in ImageTest, this is just a sanity check */ - Containers::StridedArrayView3D pixels = image.pixels(); + auto pixels = image.template pixels(); + CORRADE_COMPARE(decltype(pixels)::Dimensions, 3); + CORRADE_COMPARE(std::is_const::value, std::is_const::value); CORRADE_COMPARE(pixels.size(), (Containers::StridedArrayView3D::Size{3, 4, 2})); CORRADE_COMPARE(pixels.stride(), (Containers::StridedArrayView3D::Stride{140, 20, 3})); CORRADE_COMPARE(pixels.data(), image.data() + 140 + 2*20 + 3*3); diff --git a/src/Magnum/Trade/ImageData.cpp b/src/Magnum/Trade/ImageData.cpp index 5e0a94c6c..55d8162cf 100644 --- a/src/Magnum/Trade/ImageData.cpp +++ b/src/Magnum/Trade/ImageData.cpp @@ -93,16 +93,26 @@ template Containers::StridedArrayView(*this); } -template ImageData::operator ImageView() const -{ - CORRADE_ASSERT(!_compressed, "Trade::ImageData::type(): the image is compressed", (ImageView{_storage, _format, _formatExtra, _pixelSize, _size})); - return ImageView{_storage, _format, _formatExtra, _pixelSize, _size, _data}; +template ImageData::operator ImageView() { + CORRADE_ASSERT(!_compressed, "Trade::ImageData: the image is compressed", (ImageView{_storage, _format, _formatExtra, _pixelSize, _size})); + return ImageView{_storage, _format, _formatExtra, _pixelSize, _size, _data}; } -template ImageData::operator CompressedImageView() const -{ - CORRADE_ASSERT(_compressed, "Trade::ImageData::type(): the image is not compressed", (CompressedImageView{_compressedStorage, _compressedFormat, _size})); - return CompressedImageView{ +template ImageData::operator ImageView() const { + CORRADE_ASSERT(!_compressed, "Trade::ImageData: the image is compressed", (ImageView{_storage, _format, _formatExtra, _pixelSize, _size})); + return ImageView{_storage, _format, _formatExtra, _pixelSize, _size, _data}; +} + +template ImageData::operator CompressedImageView() { + CORRADE_ASSERT(_compressed, "Trade::ImageData: the image is not compressed", (CompressedImageView{_compressedStorage, _compressedFormat, _size})); + return CompressedImageView{ + _compressedStorage, + _compressedFormat, _size, _data}; +} + +template ImageData::operator CompressedImageView() const { + CORRADE_ASSERT(_compressed, "Trade::ImageData: the image is not compressed", (CompressedImageView{_compressedStorage, _compressedFormat, _size})); + return CompressedImageView{ _compressedStorage, _compressedFormat, _size, _data}; } diff --git a/src/Magnum/Trade/ImageData.h b/src/Magnum/Trade/ImageData.h index 90f62939a..ba9de921f 100644 --- a/src/Magnum/Trade/ImageData.h +++ b/src/Magnum/Trade/ImageData.h @@ -235,7 +235,9 @@ template class ImageData { */ /* Not restricted to const&, because we might want to pass the view to another function in an oneliner (e.g. saving screenshot) */ - /*implicit*/ operator ImageView() const; + /*implicit*/ operator ImageView(); + /** @overload */ + /*implicit*/ operator ImageView() const; /** * @brief Conversion to compressed view @@ -245,7 +247,9 @@ template class ImageData { */ /* Not restricted to const&, because we might want to pass the view to another function in an oneliner (e.g. saving screenshot) */ - /*implicit*/ operator CompressedImageView() const; + /*implicit*/ operator CompressedImageView(); + /** @overload */ + /*implicit*/ operator CompressedImageView() const; /** * @brief Storage of pixel data diff --git a/src/Magnum/Trade/Test/ImageDataTest.cpp b/src/Magnum/Trade/Test/ImageDataTest.cpp index 80a900f34..682316e02 100644 --- a/src/Magnum/Trade/Test/ImageDataTest.cpp +++ b/src/Magnum/Trade/Test/ImageDataTest.cpp @@ -55,10 +55,10 @@ struct ImageDataTest: TestSuite::Tester { void constructMoveAttachState(); void constructMoveCompressedAttachState(); - void toViewGeneric(); - void toViewImplementationSpecific(); - void toViewCompressedGeneric(); - void toViewCompressedImplementationSpecific(); + template void toViewGeneric(); + template void toViewImplementationSpecific(); + template void toViewCompressedGeneric(); + template void toViewCompressedImplementationSpecific(); void data(); void dataRvalue(); @@ -74,6 +74,18 @@ struct ImageDataTest: TestSuite::Tester { void pixelsCompressed(); }; +template struct MutabilityTraits; +template<> struct MutabilityTraits { + typedef const ImageData2D ImageType; + + static const char* name() { return "ImageView"; } +}; +template<> struct MutabilityTraits { + typedef ImageData2D ImageType; + + static const char* name() { return "MutableImageView"; } +}; + ImageDataTest::ImageDataTest() { addTests({&ImageDataTest::constructGeneric, &ImageDataTest::constructImplementationSpecific, @@ -93,10 +105,14 @@ ImageDataTest::ImageDataTest() { &ImageDataTest::constructMoveAttachState, &ImageDataTest::constructMoveCompressedAttachState, - &ImageDataTest::toViewGeneric, - &ImageDataTest::toViewImplementationSpecific, - &ImageDataTest::toViewCompressedGeneric, - &ImageDataTest::toViewCompressedImplementationSpecific, + &ImageDataTest::toViewGeneric, + &ImageDataTest::toViewGeneric, + &ImageDataTest::toViewImplementationSpecific, + &ImageDataTest::toViewImplementationSpecific, + &ImageDataTest::toViewCompressedGeneric, + &ImageDataTest::toViewCompressedGeneric, + &ImageDataTest::toViewCompressedImplementationSpecific, + &ImageDataTest::toViewCompressedImplementationSpecific, &ImageDataTest::data, &ImageDataTest::dataRvalue, @@ -500,11 +516,13 @@ void ImageDataTest::constructMoveCompressedAttachState() { CORRADE_COMPARE(b.importerState(), &stateNew); } -void ImageDataTest::toViewGeneric() { +template void ImageDataTest::toViewGeneric() { + setTestCaseTemplateName(MutabilityTraits::name()); + auto data = new char[3*4]; - const ImageData2D a{PixelStorage{}.setAlignment(1), + typename MutabilityTraits::ImageType a{PixelStorage{}.setAlignment(1), PixelFormat::RG16I, {1, 3}, Containers::Array{data, 3*4}}; - ImageView2D b = a; + ImageView<2, T> b = a; CORRADE_COMPARE(b.storage().alignment(), 1); CORRADE_COMPARE(b.format(), PixelFormat::RG16I); @@ -514,11 +532,13 @@ void ImageDataTest::toViewGeneric() { CORRADE_COMPARE(b.data(), data); } -void ImageDataTest::toViewImplementationSpecific() { +template void ImageDataTest::toViewImplementationSpecific() { + setTestCaseTemplateName(MutabilityTraits::name()); + auto data = new char[3*6]; - const ImageData2D a{PixelStorage{}.setAlignment(1), + typename MutabilityTraits::ImageType a{PixelStorage{}.setAlignment(1), GL::PixelFormat::RGB, GL::PixelType::UnsignedShort, {1, 3}, Containers::Array{data, 3*6}}; - ImageView2D b = a; + ImageView<2, T> b = a; CORRADE_COMPARE(b.storage().alignment(), 1); CORRADE_COMPARE(b.format(), pixelFormatWrap(GL::PixelFormat::RGB)); @@ -528,12 +548,14 @@ void ImageDataTest::toViewImplementationSpecific() { CORRADE_COMPARE(b.data(), data); } -void ImageDataTest::toViewCompressedGeneric() { +template void ImageDataTest::toViewCompressedGeneric() { + setTestCaseTemplateName(MutabilityTraits::name()); + auto data = new char[8]; - const ImageData2D a{ + typename MutabilityTraits::ImageType a{ CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), CompressedPixelFormat::Bc1RGBUnorm, {4, 4}, Containers::Array{data, 8}}; - CompressedImageView2D b = a; + CompressedImageView<2, T> b = a; CORRADE_COMPARE(b.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(b.format(), CompressedPixelFormat::Bc1RGBUnorm); @@ -542,12 +564,14 @@ void ImageDataTest::toViewCompressedGeneric() { CORRADE_COMPARE(b.data().size(), 8); } -void ImageDataTest::toViewCompressedImplementationSpecific() { +template void ImageDataTest::toViewCompressedImplementationSpecific() { + setTestCaseTemplateName(MutabilityTraits::name()); + auto data = new char[8]; - const ImageData2D a{ + typename MutabilityTraits::ImageType a{ CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), GL::CompressedPixelFormat::RGBS3tcDxt1, {4, 4}, Containers::Array{data, 8}}; - CompressedImageView2D b = a; + CompressedImageView<2, T> b = a; CORRADE_COMPARE(b.storage().compressedBlockSize(), Vector3i{4}); CORRADE_COMPARE(b.format(), compressedPixelFormatWrap(GL::CompressedPixelFormat::RGBS3tcDxt1));