From 413908badc5ff3cd462a161939b7fd19bedc6e21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 11 Aug 2015 16:56:45 +0200 Subject: [PATCH] Pixel storage support, part 4: the PixelStorage class. Just created, documented and used the class in images, nothing is used anywhere yet. --- src/Magnum/BufferImage.cpp | 38 +++- src/Magnum/BufferImage.h | 133 +++++++++++- src/Magnum/Image.cpp | 13 +- src/Magnum/Image.h | 166 +++++++++++++-- src/Magnum/ImageView.h | 102 ++++++++- src/Magnum/Magnum.h | 5 + src/Magnum/PixelStorage.h | 263 +++++++++++++++++++++++- src/Magnum/Test/BufferImageGLTest.cpp | 46 ++++- src/Magnum/Test/ImageTest.cpp | 56 ++++- src/Magnum/Test/ImageViewTest.cpp | 28 ++- src/Magnum/Trade/ImageData.cpp | 28 ++- src/Magnum/Trade/ImageData.h | 100 ++++++++- src/Magnum/Trade/Test/ImageDataTest.cpp | 30 ++- 13 files changed, 931 insertions(+), 77 deletions(-) diff --git a/src/Magnum/BufferImage.cpp b/src/Magnum/BufferImage.cpp index 86092993a..fcc07bb59 100644 --- a/src/Magnum/BufferImage.cpp +++ b/src/Magnum/BufferImage.cpp @@ -28,26 +28,52 @@ namespace Magnum { #ifndef MAGNUM_TARGET_GLES2 -template BufferImage::BufferImage(PixelFormat format, PixelType type, const VectorTypeFor& size, const void* data, BufferUsage usage): _format{format}, _type{type}, _size{size}, _buffer{Buffer::TargetHint::PixelPack} { +template BufferImage::BufferImage(const PixelStorage storage, const PixelFormat format, const PixelType type, const VectorTypeFor& size, const void* const data, const BufferUsage usage): _storage{storage}, _format{format}, _type{type}, _size{size}, _buffer{Buffer::TargetHint::PixelPack} { _buffer.setData({data, dataSize(size)}, usage); } -template BufferImage::BufferImage(PixelFormat format, PixelType type): _format{format}, _type{type}, _buffer{Buffer::TargetHint::PixelPack} {} +template BufferImage::BufferImage(const PixelStorage storage, const PixelFormat format, const PixelType type): _storage{storage}, _format{format}, _type{type}, _buffer{Buffer::TargetHint::PixelPack} {} -template void BufferImage::setData(PixelFormat format, PixelType type, const VectorTypeFor& size, const void* data, BufferUsage usage) { +template void BufferImage::setData(const PixelStorage storage, const PixelFormat format, const PixelType type, const VectorTypeFor& size, const void* const data, const BufferUsage usage) { + _storage = storage; _format = format; _type = type; _size = size; _buffer.setData({data, dataSize(size)}, usage); } -template CompressedBufferImage::CompressedBufferImage(CompressedPixelFormat format, const VectorTypeFor& size, Containers::ArrayView data, BufferUsage usage): _format{format}, _size{size}, _buffer{Buffer::TargetHint::PixelPack}, _dataSize{data.size()} { +template CompressedBufferImage::CompressedBufferImage( + #ifndef MAGNUM_TARGET_GLES + const CompressedPixelStorage storage, + #endif + const CompressedPixelFormat format, const VectorTypeFor& size, const Containers::ArrayView data, const BufferUsage usage): + #ifndef MAGNUM_TARGET_GLES + _storage{storage}, + #endif + _format{format}, _size{size}, _buffer{Buffer::TargetHint::PixelPack}, _dataSize{data.size()} +{ _buffer.setData(data, usage); } -template CompressedBufferImage::CompressedBufferImage(): _format{}, _buffer{Buffer::TargetHint::PixelPack}, _dataSize{} {} +template CompressedBufferImage::CompressedBufferImage( + #ifndef MAGNUM_TARGET_GLES + const CompressedPixelStorage storage + #endif + ): + #ifndef MAGNUM_TARGET_GLES + _storage{storage}, + #endif + _format{}, _buffer{Buffer::TargetHint::PixelPack}, _dataSize{} {} -template void CompressedBufferImage::setData(CompressedPixelFormat format, const VectorTypeFor& size, Containers::ArrayView data, BufferUsage usage) { +template void CompressedBufferImage::setData( + #ifndef MAGNUM_TARGET_GLES + const CompressedPixelStorage storage, + #endif + const CompressedPixelFormat format, const VectorTypeFor& size, const Containers::ArrayView data, const BufferUsage usage) +{ + #ifndef MAGNUM_TARGET_GLES + _storage = storage; + #endif _format = format; _size = size; _buffer.setData(data, usage); diff --git a/src/Magnum/BufferImage.h b/src/Magnum/BufferImage.h index 1e77fa6fd..30b86881f 100644 --- a/src/Magnum/BufferImage.h +++ b/src/Magnum/BufferImage.h @@ -57,6 +57,7 @@ template class BufferImage { /** * @brief Constructor + * @param storage Storage of pixel data * @param format Format of pixel data * @param type Data type of pixel data * @param size Image size @@ -67,17 +68,31 @@ template class BufferImage { * @todo Make it more flexible (usable with * @extension{ARB,buffer_storage}, avoiding relocations...) */ - explicit BufferImage(PixelFormat format, PixelType type, const VectorTypeFor& size, const void* data, BufferUsage usage); + explicit BufferImage(PixelStorage storage, PixelFormat format, PixelType type, const VectorTypeFor& size, const void* data, BufferUsage usage); + + /** @overload + * Similar to the above, but uses default @ref PixelStorage parameters. + */ + explicit BufferImage(PixelFormat format, PixelType type, const VectorTypeFor& size, const void* data, BufferUsage usage): BufferImage{{}, format, type, size, data, usage} {} /** * @brief Constructor + * @param storage Storage of pixel data * @param format Format of pixel data * @param type Data type of pixel data * * Size is zero and buffer are empty, call @ref setData() to fill the - * image with data. + * image with data or use @ref Texture::image() "*Texture::image()"/ + * @ref Texture::subImage() "*Texture::subImage()"/ + * @ref AbstractFramebuffer::read() "*Framebuffer::read()" to fill the + * image with data using @p storage settings. */ - /*implicit*/ BufferImage(PixelFormat format, PixelType type); + /*implicit*/ BufferImage(PixelStorage storage, PixelFormat format, PixelType type); + + /** @overload + * Similar to the above, but uses default @ref PixelStorage parameters. + */ + /*implicit*/ BufferImage(PixelFormat format, PixelType type): BufferImage{{}, format, type} {} /** @brief Copying is not allowed */ BufferImage(const BufferImage&) = delete; @@ -91,6 +106,9 @@ template class BufferImage { /** @brief Move assignment */ BufferImage& operator=(BufferImage&& other) noexcept; + /** @brief Storage of pixel data */ + PixelStorage storage() const { return _storage; } + /** @brief Format of pixel data */ PixelFormat format() const { return _format; } @@ -113,6 +131,7 @@ template class BufferImage { /** * @brief Set image data + * @param storage Storage of pixel data * @param format Format of pixel data * @param type Data type of pixel data * @param size Image size @@ -125,9 +144,17 @@ template class BufferImage { * @todo Make it more flexible (usable with * @extension{ARB,buffer_storage}, avoiding relocations...) */ - void setData(PixelFormat format, PixelType type, const VectorTypeFor& size, const void* data, BufferUsage usage); + void setData(PixelStorage storage, PixelFormat format, PixelType type, const VectorTypeFor& size, const void* data, BufferUsage usage); + + /** @overload + * Similar to the above, but uses default @ref PixelStorage parameters. + */ + void setData(PixelFormat format, PixelType type, const VectorTypeFor& size, const void* data, BufferUsage usage) { + setData({}, format, type, size, data, usage); + } private: + PixelStorage _storage; PixelFormat _format; PixelType _type; Math::Vector _size; @@ -161,9 +188,11 @@ template class CompressedBufferImage { Dimensions = dimensions /**< Image dimension count */ }; + #ifndef MAGNUM_TARGET_GLES /** * @brief Constructor - * @param format Format of compressed data + * @param storage Storage of compressed pixel data + * @param format Format of compressed pixel data * @param size Image size * @param data Image data * @param usage Image buffer usage @@ -171,14 +200,48 @@ template class CompressedBufferImage { * The data are *not* deleted after filling the buffer. * @todo Make it more flexible (usable with * @extension{ARB,buffer_storage}, avoiding relocations...) + * + * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} + * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and + * WebGL. + */ + explicit CompressedBufferImage(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor& size, Containers::ArrayView data, BufferUsage usage); + #endif + + /** + * @brief Constructor + * @param format Format of compressed pixel data + * @param size Image size + * @param data Image data + * @param usage Image buffer usage + * + * Similar the above, but uses default @ref CompressedPixelStorage + * parameters (or the hardcoded ones in OpenGL ES and WebGL). */ explicit CompressedBufferImage(CompressedPixelFormat format, const VectorTypeFor& size, Containers::ArrayView data, BufferUsage usage); + #ifndef MAGNUM_TARGET_GLES /** * @brief Constructor + * @param storage Storage of compressed pixel data * * Format is undefined, size is zero and buffer is empty, call - * @ref setData() to fill the image with data. + * @ref setData() to fill the image with data or use + * @ref Texture::compressedImage() "*Texture::compressedImage()"/ + * @ref Texture::compressedSubImage() "*Texture::compressedSubImage()" + * to fill the image with data using @p storage settings. + * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} + * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and + * WebGL. + */ + /*implicit*/ CompressedBufferImage(CompressedPixelStorage storage); + #endif + + /** + * @brief Constructor + * + * Similar the above, but uses default @ref CompressedPixelStorage + * parameters (or the hardcoded ones in OpenGL ES and WebGL). */ /*implicit*/ CompressedBufferImage(); @@ -194,7 +257,18 @@ template class CompressedBufferImage { /** @brief Move assignment */ CompressedBufferImage& operator=(CompressedBufferImage&& other) noexcept; - /** @brief Format of compressed data */ + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Storage of compressed pixel data + * + * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} + * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and + * WebGL. + */ + CompressedPixelStorage storage() const { return _storage; } + #endif + + /** @brief Format of compressed pixel data */ CompressedPixelFormat format() const { return _format; } /** @brief Image size */ @@ -206,9 +280,11 @@ template class CompressedBufferImage { /** @brief Raw data size */ std::size_t dataSize() const { return _dataSize; } + #ifndef MAGNUM_TARGET_GLES /** * @brief Set image data - * @param format Format of compressed data + * @param storage Storage of compressed pixel data + * @param format Format of compressed pixel data * @param size Image size * @param data Image data * @param usage Image buffer usage @@ -216,12 +292,31 @@ template class CompressedBufferImage { * Updates the image buffer with given data. The data are *not* deleted * after filling the buffer. * @see @ref Buffer::setData() + * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} + * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and + * WebGL. * @todo Make it more flexible (usable with * @extension{ARB,buffer_storage}, avoiding relocations...) */ + void setData(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor& size, Containers::ArrayView data, BufferUsage usage); + #endif + + /** + * @brief Set image data + * @param format Format of compressed pixel data + * @param size Image size + * @param data Image data + * @param usage Image buffer usage + * + * Similar the above, but uses default @ref CompressedPixelStorage + * parameters (or the hardcoded ones in OpenGL ES and WebGL). + */ void setData(CompressedPixelFormat format, const VectorTypeFor& size, Containers::ArrayView data, BufferUsage usage); private: + #ifndef MAGNUM_TARGET_GLES + CompressedPixelStorage _storage; + #endif CompressedPixelFormat _format; Math::Vector _size; Buffer _buffer; @@ -237,17 +332,22 @@ typedef CompressedBufferImage<2> CompressedBufferImage2D; /** @brief Three-dimensional compressed buffer image */ typedef CompressedBufferImage<3> CompressedBufferImage3D; -template inline BufferImage::BufferImage(BufferImage&& other) noexcept: _format{std::move(other._format)}, _type{std::move(other._type)}, _size{std::move(other._size)}, _buffer{std::move(other._buffer)} { +template inline BufferImage::BufferImage(BufferImage&& other) noexcept: _storage{std::move(other._storage)}, _format{std::move(other._format)}, _type{std::move(other._type)}, _size{std::move(other._size)}, _buffer{std::move(other._buffer)} { other._size = {}; } -template inline CompressedBufferImage::CompressedBufferImage(CompressedBufferImage&& other) noexcept: _format{std::move(other._format)}, _size{std::move(other._size)}, _buffer{std::move(other._buffer)}, _dataSize{std::move(other._dataSize)} { +template inline CompressedBufferImage::CompressedBufferImage(CompressedBufferImage&& other) noexcept: + #ifndef MAGNUM_TARGET_GLES + _storage{std::move(other._storage)}, + #endif + _format{std::move(other._format)}, _size{std::move(other._size)}, _buffer{std::move(other._buffer)}, _dataSize{std::move(other._dataSize)} { other._size = {}; other._dataSize = {}; } template inline BufferImage& BufferImage::operator=(BufferImage&& other) noexcept { using std::swap; + swap(_storage, other._storage); swap(_format, other._format); swap(_type, other._type); swap(_size, other._size); @@ -257,12 +357,25 @@ template inline BufferImage& BufferImage inline CompressedBufferImage& CompressedBufferImage::operator=(CompressedBufferImage&& other) noexcept { using std::swap; + #ifndef MAGNUM_TARGET_GLES + swap(_storage, other._storage); + #endif swap(_format, other._format); swap(_size, other._size); swap(_buffer, other._buffer); swap(_dataSize, other._dataSize); return *this; } + +#ifndef MAGNUM_TARGET_GLES +template inline CompressedBufferImage::CompressedBufferImage(const CompressedPixelFormat format, const VectorTypeFor& size, const Containers::ArrayView data, const BufferUsage usage): CompressedBufferImage{{}, format, size, data, usage} {} + +template inline CompressedBufferImage::CompressedBufferImage(): CompressedBufferImage{CompressedPixelStorage{}} {} + +template inline void CompressedBufferImage::setData(const CompressedPixelFormat format, const VectorTypeFor& size, const Containers::ArrayView data, const BufferUsage usage) { + setData({}, format, size, data, usage); +} +#endif #else #error this header is not available in OpenGL ES 2.0 build #endif diff --git a/src/Magnum/Image.cpp b/src/Magnum/Image.cpp index f08f803ab..a7003a513 100644 --- a/src/Magnum/Image.cpp +++ b/src/Magnum/Image.cpp @@ -27,15 +27,24 @@ namespace Magnum { -template void Image::setData(PixelFormat format, PixelType type, const VectorTypeFor& size, void* data) { +template void Image::setData(PixelStorage storage, PixelFormat format, PixelType type, const VectorTypeFor& size, void* data) { delete[] _data; + _storage = storage; _format = format; _type = type; _size = size; _data = reinterpret_cast(data); } -template void CompressedImage::setData(CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data) { +template void CompressedImage::setData( + #ifndef MAGNUM_TARGET_GLES + CompressedPixelStorage storage, + #endif + CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data) +{ + #ifndef MAGNUM_TARGET_GLES + _storage = storage; + #endif _format = format; _size = size; _data = std::move(data); diff --git a/src/Magnum/Image.h b/src/Magnum/Image.h index 6d7f42ebf..0d5970ce2 100644 --- a/src/Magnum/Image.h +++ b/src/Magnum/Image.h @@ -50,6 +50,7 @@ template class Image { /** * @brief Constructor + * @param storage Storage of pixel data * @param format Format of pixel data * @param type Data type of pixel data * @param size Image size @@ -58,17 +59,32 @@ template class Image { * Note that the image data are not copied on construction, but they * are deleted on class destruction. */ - explicit Image(PixelFormat format, PixelType type, const VectorTypeFor& size, void* data): _format{format}, _type{type}, _size{size}, _data{reinterpret_cast(data)} {} + explicit Image(PixelStorage storage, PixelFormat format, PixelType type, const VectorTypeFor& size, void* data): _storage{storage}, _format{format}, _type{type}, _size{size}, _data{reinterpret_cast(data)} {} + + /** @overload + * Similar to the above, but uses default @ref PixelStorage parameters. + */ + explicit Image(PixelFormat format, PixelType type, const VectorTypeFor& size, void* data): Image{{}, format, type, size, data} {} /** * @brief Constructor + * @param storage Storage of pixel data * @param format Format of pixel data * @param type Data type of pixel data * * Dimensions are set to zero and data pointer to `nullptr`, call - * @ref setData() to fill the image with data. + * @ref setData() to fill the image with data or use + * @ref Texture::image() "*Texture::image()"/ + * @ref Texture::subImage() "*Texture::subImage()"/ + * @ref AbstractFramebuffer::read() "*Framebuffer::read()" to fill the + * image with data using @p storage settings. + */ + /*implicit*/ Image(PixelStorage storage, PixelFormat format, PixelType type): _storage{storage}, _format{format}, _type{type}, _data{} {} + + /** @overload + * Similar to the above, but uses default @ref PixelStorage parameters. */ - /*implicit*/ Image(PixelFormat format, PixelType type): _format{format}, _type{type}, _data{} {} + /*implicit*/ Image(PixelFormat format, PixelType type): Image{{}, format, type} {} /** @brief Copying is not allowed */ Image(const Image&) = delete; @@ -98,6 +114,9 @@ template class Image { /*implicit*/ operator ImageView() const && = delete; #endif + /** @brief Storage of pixel data */ + PixelStorage storage() const { return _storage; } + /** @brief Format of pixel data */ PixelFormat format() const { return _format; } @@ -137,6 +156,7 @@ template class Image { /** * @brief Set image data + * @param storage Storage of pixel data * @param format Format of pixel data * @param type Data type of pixel data * @param size Image size @@ -146,7 +166,14 @@ template class Image { * data are not copied, but they are deleted on destruction. * @see @ref release() */ - void setData(PixelFormat format, PixelType type, const VectorTypeFor& size, void* data); + void setData(PixelStorage storage, PixelFormat format, PixelType type, const VectorTypeFor& size, void* data); + + /** @overload + * Similar to the above, but uses default @ref PixelStorage parameters. + */ + void setData(PixelFormat format, PixelType type, const VectorTypeFor& size, void* data) { + setData({}, format, type, size, data); + } /** * @brief Release data storage @@ -158,6 +185,7 @@ template class Image { char* release(); private: + PixelStorage _storage; PixelFormat _format; PixelType _type; Math::Vector _size; @@ -188,21 +216,57 @@ template class CompressedImage { Dimensions = dimensions /**< Image dimension count */ }; + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Constructor + * @param storage Storage of compressed pixel data + * @param format Format of compressed pixel data + * @param size Image size + * @param data Image data + * + * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} + * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and + * WebGL. + */ + explicit CompressedImage(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data); + #endif + /** * @brief Constructor - * @param format Format of compressed data + * @param format Format of compressed pixel data * @param size Image size * @param data Image data + * + * Similar the above, but uses default @ref CompressedPixelStorage + * parameters (or the hardcoded ones in OpenGL ES and WebGL). */ - explicit CompressedImage(CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data): _format{format}, _size{size}, _data{std::move(data)} {} + explicit CompressedImage(CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data); + #ifndef MAGNUM_TARGET_GLES /** * @brief Constructor + * @param storage Storage of compressed pixel data * * Format is undefined, size is zero and data are empty, call - * @ref setData() to fill the image with data. + * @ref setData() to fill the image with data or use + * @ref Texture::compressedImage() "*Texture::compressedImage()"/ + * @ref Texture::compressedSubImage() "*Texture::compressedSubImage()" + * to fill the image with data using @p storage settings. + * + * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} + * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and + * WebGL. */ - /*implicit*/ CompressedImage(): _format{} {} + /*implicit*/ CompressedImage(CompressedPixelStorage storage); + #endif + + /** + * @brief Constructor + * + * Similar the above, but uses default @ref CompressedPixelStorage + * parameters (or the hardcoded ones in OpenGL ES). + */ + /*implicit*/ CompressedImage(); /** @brief Copying is not allowed */ CompressedImage(const CompressedImage&) = delete; @@ -229,7 +293,18 @@ template class CompressedImage { /*implicit*/ operator CompressedImageView() const && = delete; #endif - /** @brief Format of compressed data */ + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Storage of compressed pixel data + * + * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} + * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and + * WebGL. + */ + CompressedPixelStorage storage() const { return _storage; } + #endif + + /** @brief Format of compressed pixel data */ CompressedPixelFormat format() const { return _format; } /** @brief Image size */ @@ -255,15 +330,32 @@ template class CompressedImage { return reinterpret_cast(_data.data()); } + #ifndef MAGNUM_TARGET_GLES /** * @brief Set image data - * @param format Format of compressed data + * @param storage Storage of compressed pixel data + * @param format Format of compressed pixel data * @param size Image size * @param data Image data * * Deletes previous data and replaces them with new. Note that the * data are not copied, but they are deleted on destruction. * @see @ref release() + * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} + * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and + * WebGL. + */ + void setData(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data); + #endif + + /** + * @brief Set image data + * @param format Format of compressed pixel data + * @param size Image size + * @param data Image data + * + * Similar the above, but uses default @ref CompressedPixelStorage + * parameters (or the hardcoded ones in OpenGL ES and WebGL). */ void setData(CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data); @@ -277,6 +369,9 @@ template class CompressedImage { Containers::Array release(); private: + #ifndef MAGNUM_TARGET_GLES + CompressedPixelStorage _storage; + #endif CompressedPixelFormat _format; Math::Vector _size; Containers::Array _data; @@ -291,18 +386,24 @@ typedef CompressedImage<2> CompressedImage2D; /** @brief Three-dimensional compressed image */ typedef CompressedImage<3> CompressedImage3D; -template inline Image::Image(Image&& other) noexcept: _format{std::move(other._format)}, _type{std::move(other._type)}, _size{std::move(other._size)}, _data{std::move(other._data)} { +template inline Image::Image(Image&& other) noexcept: _storage{std::move(other._storage)}, _format{std::move(other._format)}, _type{std::move(other._type)}, _size{std::move(other._size)}, _data{std::move(other._data)} { other._size = {}; other._data = nullptr; } -template inline CompressedImage::CompressedImage(CompressedImage&& other) noexcept: _format{std::move(other._format)}, _size{std::move(other._size)}, _data{std::move(other._data)} { +template inline CompressedImage::CompressedImage(CompressedImage&& other) noexcept: + #ifndef MAGNUM_TARGET_GLES + _storage{std::move(other._storage)}, + #endif + _format{std::move(other._format)}, _size{std::move(other._size)}, _data{std::move(other._data)} +{ other._size = {}; other._data = nullptr; } template inline Image& Image::operator=(Image&& other) noexcept { using std::swap; + swap(_storage, other._storage); swap(_format, other._format); swap(_type, other._type); swap(_size, other._size); @@ -312,6 +413,9 @@ template inline Image& Image::op template inline CompressedImage& CompressedImage::operator=(CompressedImage&& other) noexcept { using std::swap; + #ifndef MAGNUM_TARGET_GLES + swap(_storage, other._storage); + #endif swap(_format, other._format); swap(_size, other._size); swap(_data, other._data); @@ -325,7 +429,7 @@ const & const #endif { - return ImageView{_format, _type, _size, _data}; + return ImageView{_storage, _format, _type, _size, _data}; } template inline CompressedImage::operator CompressedImageView() @@ -335,7 +439,11 @@ const & const #endif { - return CompressedImageView{_format, _size, _data}; + return CompressedImageView{ + #ifndef MAGNUM_TARGET_GLES + _storage, + #endif + _format, _size, _data}; } template inline char* Image::release() { @@ -354,6 +462,36 @@ template inline Containers::Array CompressedImage< return data; } +template inline CompressedImage::CompressedImage( + #ifndef MAGNUM_TARGET_GLES + const CompressedPixelStorage storage, + #endif + const CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data): + #ifndef MAGNUM_TARGET_GLES + _storage{storage}, + #endif + _format{format}, _size{size}, _data{std::move(data)} {} + +template inline CompressedImage::CompressedImage( + #ifndef MAGNUM_TARGET_GLES + const CompressedPixelStorage storage + #endif + ) + #ifndef MAGNUM_TARGET_GLES + : _storage{storage} + #endif + {} + +#ifndef MAGNUM_TARGET_GLES +template inline CompressedImage::CompressedImage(const CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data): CompressedImage{{}, format, size, std::move(data)} {} + +template inline CompressedImage::CompressedImage(): CompressedImage{CompressedPixelStorage{}} {} + +template inline void CompressedImage::setData(const CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data) { + setData({}, format, size, std::move(data)); +} +#endif + } #endif diff --git a/src/Magnum/ImageView.h b/src/Magnum/ImageView.h index d3ee0f69b..b44d31153 100644 --- a/src/Magnum/ImageView.h +++ b/src/Magnum/ImageView.h @@ -61,15 +61,22 @@ template class ImageView { /** * @brief Constructor + * @param storage Storage of pixel data * @param format Format of pixel data * @param type Data type of pixel data * @param size Image size * @param data Image data */ - constexpr explicit ImageView(PixelFormat format, PixelType type, const VectorTypeFor& size, const void* data): _format{format}, _type{type}, _size{size}, _data{reinterpret_cast(data)} {} + constexpr explicit ImageView(PixelStorage storage, PixelFormat format, PixelType type, const VectorTypeFor& size, const void* data) noexcept: _storage{storage}, _format{format}, _type{type}, _size{size}, _data{reinterpret_cast(data)} {} + + /** @overload + * Similar to the above, but uses default @ref PixelStorage parameters. + */ + constexpr explicit ImageView(PixelFormat format, PixelType type, const VectorTypeFor& size, const void* data) noexcept: ImageView{{}, format, type, size, data} {} /** * @brief Constructor + * @param storage Storage of pixel data * @param format Format of pixel data * @param type Data type of pixel data * @param size Image size @@ -77,7 +84,15 @@ template class ImageView { * Data pointer is set to `nullptr`, call @ref setData() to fill the * image with data. */ - constexpr explicit ImageView(PixelFormat format, PixelType type, const VectorTypeFor& size): _format{format}, _type{type}, _size{size}, _data{nullptr} {} + constexpr explicit ImageView(PixelStorage storage, PixelFormat format, PixelType type, const VectorTypeFor& size) noexcept: _storage{storage}, _format{format}, _type{type}, _size{size}, _data{nullptr} {} + + /** @overload + * Similar to the above, but uses default @ref PixelStorage parameters. + */ + constexpr explicit ImageView(PixelFormat format, PixelType type, const VectorTypeFor& size) noexcept: ImageView{{}, format, type, size} {} + + /** @brief Storage of pixel data */ + PixelStorage storage() const { return _storage; } /** @brief Format of pixel data */ PixelFormat format() const { return _format; } @@ -117,6 +132,7 @@ template class ImageView { } private: + PixelStorage _storage; PixelFormat _format; PixelType _type; Math::Vector _size; @@ -148,23 +164,68 @@ template class CompressedImageView { Dimensions = dimensions /**< Image dimension count */ }; + #ifndef MAGNUM_TARGET_GLES /** * @brief Constructor - * @param format Format of compressed data + * @param storage Storage of compressed pixel data + * @param format Format of compressed pixel data * @param size Image size * @param data Image data + * + * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} + * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and + * WebGL. + */ + constexpr explicit CompressedImageView(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor& size, Containers::ArrayView data) noexcept; + #endif + + /** + * @brief Constructor + * @param format Format of compressed pixel data + * @param size Image size + * @param data Image data + * + * Similar the above, but uses default @ref CompressedPixelStorage + * parameters (or the hardcoded ones in OpenGL ES and WebGL). */ - constexpr explicit CompressedImageView(CompressedPixelFormat format, const VectorTypeFor& size, Containers::ArrayView data): _format{format}, _size{size}, _data{reinterpret_cast(data.data()), data.size()} {} + constexpr explicit CompressedImageView(CompressedPixelFormat format, const VectorTypeFor& size, Containers::ArrayView data) noexcept; + #ifndef MAGNUM_TARGET_GLES /** * @brief Constructor - * @param format Format of compressed data + * @param storage Storage of compressed pixel data + * @param format Format of compressed pixel data * @param size Image size * * Data pointer is set to `nullptr`, call @ref setData() to fill the * image with data. + * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} + * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and + * WebGL. */ - constexpr explicit CompressedImageView(CompressedPixelFormat format, const VectorTypeFor& size): _format{format}, _size{size} {} + constexpr explicit CompressedImageView(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor& size) noexcept; + #endif + + /** + * @brief Constructor + * @param format Format of compressed pixel data + * @param size Image size + * + * Similar the above, but uses default @ref CompressedPixelStorage + * parameters (or the hardcoded ones in OpenGL ES and WebGL). + */ + constexpr explicit CompressedImageView(CompressedPixelFormat format, const VectorTypeFor& size) noexcept; + + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Storage of compressed pixel data + * + * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} + * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and + * WebGL. + */ + CompressedPixelStorage storage() const { return _storage; } + #endif /** @brief Format of compressed data */ CompressedPixelFormat format() const { return _format; } @@ -193,6 +254,9 @@ template class CompressedImageView { } private: + #ifndef MAGNUM_TARGET_GLES + CompressedPixelStorage _storage; + #endif CompressedPixelFormat _format; Math::Vector _size; Containers::ArrayView _data; @@ -207,6 +271,32 @@ typedef CompressedImageView<2> CompressedImageView2D; /** @brief Three-dimensional compressed image view */ typedef CompressedImageView<3> CompressedImageView3D; +template constexpr CompressedImageView::CompressedImageView( + #ifndef MAGNUM_TARGET_GLES + const CompressedPixelStorage storage, + #endif + const CompressedPixelFormat format, const VectorTypeFor& size, const Containers::ArrayView data) noexcept: + #ifndef MAGNUM_TARGET_GLES + _storage{storage}, + #endif + _format{format}, _size{size}, _data{reinterpret_cast(data.data()), data.size()} {} + +template constexpr CompressedImageView::CompressedImageView( + #ifndef MAGNUM_TARGET_GLES + const CompressedPixelStorage storage, + #endif + const CompressedPixelFormat format, const VectorTypeFor& size) noexcept: + #ifndef MAGNUM_TARGET_GLES + _storage{storage}, + #endif + _format{format}, _size{size} {} + +#ifndef MAGNUM_TARGET_GLES +template constexpr CompressedImageView::CompressedImageView(const CompressedPixelFormat format, const VectorTypeFor& size, const Containers::ArrayView data) noexcept: CompressedImageView{{}, format, size, data} {} + +template constexpr CompressedImageView::CompressedImageView(const CompressedPixelFormat format, const VectorTypeFor& size) noexcept: CompressedImageView{{}, format, size} {} +#endif + } #endif diff --git a/src/Magnum/Magnum.h b/src/Magnum/Magnum.h index c07a452de..02356c487 100644 --- a/src/Magnum/Magnum.h +++ b/src/Magnum/Magnum.h @@ -533,6 +533,11 @@ typedef CORRADE_DEPRECATED("use PixelType instead") PixelType ColorType; typedef CORRADE_DEPRECATED("use CompressedPixelFormat instead") CompressedPixelFormat CompressedColorFormat; #endif +class PixelStorage; +#ifndef MAGNUM_TARGET_GLES +class CompressedPixelStorage; +#endif + /* ObjectFlag, ObjectFlags are used only in conjunction with *::wrap() function */ class PrimitiveQuery; diff --git a/src/Magnum/PixelStorage.h b/src/Magnum/PixelStorage.h index cd0bf1519..065926712 100644 --- a/src/Magnum/PixelStorage.h +++ b/src/Magnum/PixelStorage.h @@ -26,13 +26,14 @@ */ /** @file - * @brief + * @brief Class @ref Magnum::PixelStorage, @ref Magnum::CompressedPixelStorage */ #include #include "Magnum/Magnum.h" #include "Magnum/visibility.h" +#include "Magnum/Math/Vector3.h" namespace Magnum { @@ -42,6 +43,266 @@ namespace Implementation { template std::size_t imageDataSize(PixelFormat format, PixelType type, Math::Vector size); } +/** +@brief Pixel storage parameters + +Descibes how to interpret data which are read from or stored into @ref Image, +@ref ImageView, @ref BufferImage and @ref Trade::ImageData using +@ref Texture::setImage() "*Texture::setImage()", @ref Texture::setSubImage() "*Texture::setSubImage()", +@ref Texture::image() "*Texture::image()", @ref Texture::subImage() "*Texture::subImage()" +and @ref AbstractFramebuffer::read() "*Framebuffer::read()". + +## Performance optimizations + +The storage mode is applied either right before doing image upload using +@fn_gl{PixelStore} with @def_gl{UNPACK_*} parameters or right before doing +image download using @fn_gl{PixelStore} with @def_gl{PACK_*}. The engine tracks +currently used pixel pack/unpack parameters to avoid unnecessary calls to +@fn_gl{PixelStore}. See also @ref Context::resetState() and +@ref Context::State::PixelStorage. + +@see @ref CompressedPixelStorage +*/ +class PixelStorage { + public: + /** + * @brief Default constructor + * + * Sets all parameters to default values, i.e. all values set to + * `false`/`0` except for alignment, which is `4`. + */ + constexpr /*implicit*/ PixelStorage() noexcept; + + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Whether to reverse byte order + * + * @requires_gl Not available in OpenGL ES or WebGL. + */ + constexpr bool swapBytes() const { return _swapBytes; } + + /** + * @brief Enable or disable byte order reversion + * + * Not applicable for @ref CompressedPixelStorage. Default is `false`. + * @see @fn_gl{PixelStore} with @def_gl{PACK_SWAP_BYTES}/ + * @def_gl{UNPACK_SWAP_BYTES} + * @requires_gl Not available in OpenGL ES or WebGL. + */ + PixelStorage& setSwapBytes(bool enabled) { + _swapBytes = enabled; + return *this; + } + #endif + + /** @brief Row alignment */ + constexpr Int alignment() const { return _alignment; } + + /** + * @brief Set row alignment + * + * Not applicable for @ref CompressedPixelStorage. Valid values are + * `1`, `2`, `4` and `8`. Default is `4`. + * @see @fn_gl{PixelStore} with @def_gl{PACK_ALIGNMENT}/ + * @def_gl{UNPACK_ALIGNMENT} + */ + PixelStorage& setAlignment(Int alignment) { + _alignment = alignment; + return *this; + } + + #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) + /** + * @brief Row length + * + * @requires_gles30 Extension @es_extension{EXT,unpack_subimage}/ + * @es_extension{NV,pack_subimage} in OpenGL ES 2.0. + * @requires_webgl20 Row length specification is not available in WebGL + * 1.0. + */ + constexpr Int rowLength() const { return _rowLength; } + + /** + * @brief Set row length + * + * Used only on 2D and 3D images. If set to `0`, size information from + * actual image is used. Default is `0`. + * @see @fn_gl{PixelStore} with @def_gl{UNPACK_ROW_LENGTH}/ + * @def_gl{PACK_ROW_LENGTH} + * @requires_gles30 Extension @es_extension{EXT,unpack_subimage}/ + * @es_extension{NV,pack_subimage} in OpenGL ES 2.0. + * @requires_webgl20 Row length specification is not available in WebGL + * 1.0. + */ + PixelStorage& setRowLength(Int length) { + _rowLength = length; + return *this; + } + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * @brief Image height + * + * @requires_gles30 Image height specification is not available in + * OpenGL ES 2.0 + * @requires_webgl20 Image height specification is not available in + * WebGL 1.0. + */ + constexpr Int imageHeight() const { return _imageHeight; } + + /** + * @brief Set image height + * + * Used only on 3D images. If set to `0`, size information from actual + * image is used. Default is `0`. + * @see @fn_gl{PixelStore} with @def_gl{UNPACK_IMAGE_HEIGHT}/ + * @def_gl{PACK_IMAGE_HEIGHT} + * @requires_gles30 Image height specification is not available in + * OpenGL ES 2.0 + * @requires_webgl20 Image height specification is not available in + * WebGL 1.0. + * @requires_gl Image height specification is available only for unpack + * in OpenGL ES and WebGL. + */ + PixelStorage& setImageHeight(Int height) { + _imageHeight = height; + return *this; + } + #endif + + /** @brief Pixel, row and image skipping */ + constexpr Vector3i skip() const { return _skip; } + + /** + * @brief Set pixel, row and image skipping + * + * The Y value is used only for 2D and 3D images, the Z value is used + * only for 3D images. Default is `0`. On OpenGL ES 2.0 and WebGL 1.0 + * the functionality is emulated by increasing the data pointer. + * @see @fn_gl{PixelStore} with @def_gl{UNPACK_SKIP_PIXELS}/ + * @def_gl{PACK_SKIP_PIXELS}, @def_gl{UNPACK_SKIP_ROWS}/ + * @def_gl{PACK_SKIP_ROWS}, @def_gl{UNPACK_SKIP_IMAGES}/ + * @def_gl{PACK_SKIP_IMAGES} + * @requires_gl Image skip specification is available only for unpack + * in OpenGL ES and WebGL. + */ + PixelStorage& setSkip(const Vector3i& skip) { + _skip = skip; + return *this; + } + + private: + #ifndef MAGNUM_TARGET_GLES + bool _swapBytes; + #endif + Int _alignment; + #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) + Int _rowLength; + #endif + #ifndef MAGNUM_TARGET_GLES2 + Int _imageHeight; + #endif + Vector3i _skip; +}; + +#ifndef MAGNUM_TARGET_GLES +/** +@brief Compressed pixel storage parameters + +Descibes how to interpret data which are read from or stored into +@ref CompressedImage, @ref CompressedImageView, @ref CompressedBufferImage and +@ref Trade::ImageData using @ref Texture::setCompressedImage() "*Texture::setCompressedImage(), +@ref Texture::setCompressedSubImage() "*Texture::setCompressedSubImage()", +@ref Texture::compressedImage() "*Texture::compressedImage()" and +@ref Texture::compressedSubImage() "*Texture::compressedSubImage()". + +Includes all parameters from @ref PixelStorage, except for @ref swapBytes() and +@ref alignment(), which are ignored for compressed images. + +@requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} +@requires_gl Compressed pixel storage is hardcoded in OpenGL ES and WebGL. +*/ +class CompressedPixelStorage: public PixelStorage { + public: + /** + * @brief Default constructor + * + * Sets all parameters to default values, i.e. all values set to + * `false`/`0` except for alignment, which is `4`. + */ + constexpr /*implicit*/ CompressedPixelStorage() noexcept: _blockSize{0}, _blockDataSize{0} {} + + /** @brief Compressed block size */ + constexpr Vector3i compressedBlockSize() const { return _blockSize; } + + /** + * @brief Set compressed block size + * + * If set to `0` for given dimension, size information from particular + * compressed format is used. Default is `0` in all dimensions. + */ + CompressedPixelStorage& setCompressedBlockSize(const Vector3i& size) { + _blockSize = size; + return *this; + } + + /** @brief Compressed block data size (in bytes) */ + constexpr Int compressedBlockDataSize() const { return _blockDataSize; } + + /** + * @brief Set compressed block data size (in bytes) + * + * If set to `0`, size information from particular compressed format is + * used. Default is `0` in all dimensions. + */ + CompressedPixelStorage& setCompressedBlockDataSize(Int size) { + _blockDataSize = size; + return *this; + } + + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + CompressedPixelStorage& setRowLength(Int length) { + PixelStorage::setRowLength(length); + return *this; + } + CompressedPixelStorage& setImageHeight(Int height) { + PixelStorage::setImageHeight(height); + return *this; + } + CompressedPixelStorage& setSkip(const Vector3i& skip) { + PixelStorage::setSkip(skip); + return *this; + } + #endif + + private: + #ifndef MAGNUM_TARGET_GLES + using PixelStorage::swapBytes; + using PixelStorage::setSwapBytes; + #endif + using PixelStorage::alignment; + using PixelStorage::setAlignment; + + Vector3i _blockSize; + Int _blockDataSize; +}; +#endif + +constexpr PixelStorage::PixelStorage() noexcept: + #ifndef MAGNUM_TARGET_GLES + _swapBytes{false}, + #endif + _alignment{4}, + #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) + _rowLength{0}, + #endif + #ifndef MAGNUM_TARGET_GLES2 + _imageHeight{0}, + #endif + _skip{0} {} + } #endif diff --git a/src/Magnum/Test/BufferImageGLTest.cpp b/src/Magnum/Test/BufferImageGLTest.cpp index b66f4ed35..71a254af5 100644 --- a/src/Magnum/Test/BufferImageGLTest.cpp +++ b/src/Magnum/Test/BufferImageGLTest.cpp @@ -59,7 +59,8 @@ BufferImageGLTest::BufferImageGLTest() { void BufferImageGLTest::construct() { const char data[] = { 'a', 0, 0, 0, 'b', 0, 0, 0, 'c', 0, 0, 0 }; - BufferImage2D a(PixelFormat::Red, PixelType::UnsignedByte, {1, 3}, data, BufferUsage::StaticDraw); + BufferImage2D a{PixelStorage{}.setAlignment(1), + PixelFormat::Red, PixelType::UnsignedByte, {1, 3}, data, BufferUsage::StaticDraw}; #ifndef MAGNUM_TARGET_GLES const auto imageData = a.buffer().data(); @@ -67,6 +68,7 @@ void BufferImageGLTest::construct() { MAGNUM_VERIFY_NO_ERROR(); + CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), PixelFormat::Red); CORRADE_COMPARE(a.type(), PixelType::UnsignedByte); CORRADE_COMPARE(a.size(), Vector2i(1, 3)); @@ -80,7 +82,12 @@ void BufferImageGLTest::construct() { void BufferImageGLTest::constructCompressed() { const char data[] = { 'a', 0, 0, 0, 'b', 0, 0, 0 }; - CompressedBufferImage2D a{CompressedPixelFormat::RGBAS3tcDxt1, {4, 4}, data, BufferUsage::StaticDraw}; + CompressedBufferImage2D a{ + #ifndef MAGNUM_TARGET_GLES + CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), + #endif + CompressedPixelFormat::RGBAS3tcDxt1, + {4, 4}, data, BufferUsage::StaticDraw}; #ifndef MAGNUM_TARGET_GLES const auto imageData = a.buffer().data(); @@ -88,6 +95,9 @@ void BufferImageGLTest::constructCompressed() { MAGNUM_VERIFY_NO_ERROR(); + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{4}); + #endif CORRADE_COMPARE(a.format(), CompressedPixelFormat::RGBAS3tcDxt1); CORRADE_COMPARE(a.size(), Vector2i(4, 4)); CORRADE_COMPARE(a.dataSize(), 8); @@ -111,7 +121,7 @@ void BufferImageGLTest::constructCopyCompressed() { void BufferImageGLTest::constructMove() { const char data[4] = { 'a', 'b', 'c', 'd' }; - BufferImage2D a(PixelFormat::Red, PixelType::UnsignedByte, {4, 1}, data, BufferUsage::StaticDraw); + BufferImage2D a{PixelFormat::Red, PixelType::UnsignedByte, {4, 1}, data, BufferUsage::StaticDraw}; const Int id = a.buffer().id(); MAGNUM_VERIFY_NO_ERROR(); @@ -122,13 +132,15 @@ void BufferImageGLTest::constructMove() { CORRADE_COMPARE(a.buffer().id(), 0); CORRADE_COMPARE(a.size(), Vector2i()); + CORRADE_COMPARE(b.storage().alignment(), 4); CORRADE_COMPARE(b.format(), PixelFormat::Red); CORRADE_COMPARE(b.type(), PixelType::UnsignedByte); CORRADE_COMPARE(b.size(), Vector2i(4, 1)); CORRADE_COMPARE(b.buffer().id(), id); const unsigned short data2[2*4] = { 1, 2, 3, 4, 5, 6, 7, 8 }; - BufferImage2D c(PixelFormat::RGBA, PixelType::UnsignedShort, {1, 2}, data2, BufferUsage::StaticDraw); + BufferImage2D c{PixelStorage{}.setAlignment(1), + PixelFormat::RGBA, PixelType::UnsignedShort, {1, 2}, data2, BufferUsage::StaticDraw}; const Int cId = c.buffer().id(); c = std::move(b); @@ -138,6 +150,7 @@ void BufferImageGLTest::constructMove() { CORRADE_COMPARE(b.buffer().id(), cId); CORRADE_COMPARE(b.size(), Vector2i(1, 2)); + CORRADE_COMPARE(c.storage().alignment(), 4); CORRADE_COMPARE(c.format(), PixelFormat::Red); CORRADE_COMPARE(c.type(), PixelType::UnsignedByte); CORRADE_COMPARE(c.size(), Vector2i(4, 1)); @@ -158,13 +171,20 @@ void BufferImageGLTest::constructMoveCompressed() { CORRADE_COMPARE(a.size(), Vector2i()); CORRADE_COMPARE(a.dataSize(), 0); + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE(b.storage().compressedBlockSize(), Vector3i{0}); + #endif CORRADE_COMPARE(b.format(), CompressedPixelFormat::RGBAS3tcDxt1); CORRADE_COMPARE(b.size(), Vector2i(4, 4)); CORRADE_COMPARE(b.dataSize(), 8); CORRADE_COMPARE(b.buffer().id(), id); const unsigned char data2[] = { 'a', 0, 0, 0, 'b', 0, 0, 0, 'c', 0, 0, 0, 'd', 0, 0, 0 }; - CompressedBufferImage2D c{CompressedPixelFormat::RGBAS3tcDxt1, {8, 4}, data2, BufferUsage::StaticDraw}; + CompressedBufferImage2D c{ + #ifndef MAGNUM_TARGET_GLES + CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), + #endif + CompressedPixelFormat::RGBAS3tcDxt1, {8, 4}, data2, BufferUsage::StaticDraw}; const Int cId = c.buffer().id(); c = std::move(b); @@ -175,6 +195,9 @@ void BufferImageGLTest::constructMoveCompressed() { CORRADE_COMPARE(b.size(), Vector2i(8, 4)); CORRADE_COMPARE(b.dataSize(), 16); + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE(c.storage().compressedBlockSize(), Vector3i{0}); + #endif CORRADE_COMPARE(c.format(), CompressedPixelFormat::RGBAS3tcDxt1); CORRADE_COMPARE(c.size(), Vector2i(4, 4)); CORRADE_COMPARE(c.dataSize(), 8); @@ -183,7 +206,8 @@ void BufferImageGLTest::constructMoveCompressed() { void BufferImageGLTest::setData() { const char data[4] = { 'a', 'b', 'c', 'd' }; - BufferImage2D a(PixelFormat::Red, PixelType::UnsignedByte, {4, 1}, data, BufferUsage::StaticDraw); + BufferImage2D a{PixelStorage{}.setAlignment(1), + PixelFormat::Red, PixelType::UnsignedByte, {4, 1}, data, BufferUsage::StaticDraw}; const UnsignedShort data2[2*4] = { 1, 2, 3, 4, 5, 6, 7, 8 }; a.setData(PixelFormat::RGBA, PixelType::UnsignedShort, {1, 2}, data2, BufferUsage::StaticDraw); @@ -194,6 +218,7 @@ void BufferImageGLTest::setData() { MAGNUM_VERIFY_NO_ERROR(); + CORRADE_COMPARE(a.storage().alignment(), 4); CORRADE_COMPARE(a.format(), PixelFormat::RGBA); CORRADE_COMPARE(a.type(), PixelType::UnsignedShort); CORRADE_COMPARE(a.size(), Vector2i(1, 2)); @@ -210,7 +235,11 @@ void BufferImageGLTest::setDataCompressed() { CompressedBufferImage2D a{CompressedPixelFormat::RGBAS3tcDxt1, {4, 4}, data, BufferUsage::StaticDraw}; const char data2[] = { 'a', 0, 0, 0, 'b', 0, 0, 0, 'c', 0, 0, 0, 'd', 0, 0, 0 }; - a.setData(CompressedPixelFormat::RGBAS3tcDxt3, {8, 4}, data2, BufferUsage::StaticDraw); + a.setData( + #ifndef MAGNUM_TARGET_GLES + CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), + #endif + CompressedPixelFormat::RGBAS3tcDxt3, {8, 4}, data2, BufferUsage::StaticDraw); #ifndef MAGNUM_TARGET_GLES const auto imageData = a.buffer().data(); @@ -218,6 +247,9 @@ void BufferImageGLTest::setDataCompressed() { MAGNUM_VERIFY_NO_ERROR(); + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{4}); + #endif CORRADE_COMPARE(a.format(), CompressedPixelFormat::RGBAS3tcDxt3); CORRADE_COMPARE(a.size(), Vector2i(8, 4)); CORRADE_COMPARE(a.dataSize(), 16); diff --git a/src/Magnum/Test/ImageTest.cpp b/src/Magnum/Test/ImageTest.cpp index ef24bb5f9..e729fb82b 100644 --- a/src/Magnum/Test/ImageTest.cpp +++ b/src/Magnum/Test/ImageTest.cpp @@ -66,8 +66,10 @@ ImageTest::ImageTest() { void ImageTest::construct() { auto data = new char[3]; - Image2D a(PixelFormat::Red, PixelType::UnsignedByte, {1, 3}, data); + Image2D a{PixelStorage{}.setAlignment(1), + PixelFormat::Red, PixelType::UnsignedByte, {1, 3}, data}; + CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), PixelFormat::Red); CORRADE_COMPARE(a.type(), PixelType::UnsignedByte); CORRADE_COMPARE(a.size(), Vector2i(1, 3)); @@ -76,8 +78,15 @@ void ImageTest::construct() { void ImageTest::constructCompressed() { auto data = new char[8]; - CompressedImage2D a{CompressedPixelFormat::RGBAS3tcDxt1, {4, 4}, Containers::Array{data, 8}}; + CompressedImage2D a{ + #ifndef MAGNUM_TARGET_GLES + CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), + #endif + CompressedPixelFormat::RGBAS3tcDxt1, {4, 4}, Containers::Array{data, 8}}; + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{4}); + #endif CORRADE_COMPARE(a.format(), CompressedPixelFormat::RGBAS3tcDxt1); CORRADE_COMPARE(a.size(), Vector2i(4, 4)); CORRADE_COMPARE(a.data(), data); @@ -96,12 +105,14 @@ void ImageTest::constructCopyCompressed() { void ImageTest::constructMove() { auto data = new char[3]; - Image2D a(PixelFormat::Red, PixelType::UnsignedByte, {1, 3}, data); + Image2D a{PixelStorage{}.setAlignment(1), + PixelFormat::Red, PixelType::UnsignedByte, {1, 3}, data}; Image2D b(std::move(a)); CORRADE_COMPARE(a.data(), nullptr); CORRADE_COMPARE(a.size(), Vector2i()); + CORRADE_COMPARE(b.storage().alignment(), 1); CORRADE_COMPARE(b.format(), PixelFormat::Red); CORRADE_COMPARE(b.type(), PixelType::UnsignedByte); CORRADE_COMPARE(b.size(), Vector2i(1, 3)); @@ -114,6 +125,7 @@ void ImageTest::constructMove() { CORRADE_COMPARE(b.data(), data2); CORRADE_COMPARE(b.size(), Vector2i(2, 6)); + CORRADE_COMPARE(c.storage().alignment(), 1); CORRADE_COMPARE(c.format(), PixelFormat::Red); CORRADE_COMPARE(c.type(), PixelType::UnsignedByte); CORRADE_COMPARE(c.size(), Vector2i(1, 3)); @@ -128,19 +140,29 @@ void ImageTest::constructMoveCompressed() { CORRADE_COMPARE(a.data(), nullptr); CORRADE_COMPARE(a.size(), Vector2i()); + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE(b.storage().compressedBlockSize(), Vector3i{0}); + #endif CORRADE_COMPARE(b.format(), CompressedPixelFormat::RGBAS3tcDxt1); CORRADE_COMPARE(b.size(), Vector2i(4, 4)); CORRADE_COMPARE(b.data(), data); CORRADE_COMPARE(b.data().size(), 8); auto data2 = new char[16]; - CompressedImage2D c{CompressedPixelFormat::RGBAS3tcDxt3, {8, 4}, Containers::Array{data2, 16}}; + CompressedImage2D c{ + #ifndef MAGNUM_TARGET_GLES + CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), + #endif + CompressedPixelFormat::RGBAS3tcDxt3, {8, 4}, Containers::Array{data2, 16}}; c = std::move(b); CORRADE_COMPARE_AS(b.data(), data2, char*); CORRADE_COMPARE(b.data().size(), 16); CORRADE_COMPARE(b.size(), Vector2i(8, 4)); + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE(c.storage().compressedBlockSize(), Vector3i{0}); + #endif CORRADE_COMPARE(c.format(), CompressedPixelFormat::RGBAS3tcDxt1); CORRADE_COMPARE(c.size(), Vector2i(4, 4)); CORRADE_COMPARE(c.data(), data); @@ -149,10 +171,12 @@ void ImageTest::constructMoveCompressed() { void ImageTest::setData() { auto data = new char[3]; - Image2D a(PixelFormat::Red, PixelType::UnsignedByte, {1, 3}, data); + Image2D a{PixelStorage{}.setAlignment(1), + PixelFormat::Red, PixelType::UnsignedByte, {1, 3}, data}; auto data2 = new char[2*4]; a.setData(PixelFormat::RGBA, PixelType::UnsignedShort, {2, 1}, data2); + CORRADE_COMPARE(a.storage().alignment(), 4); CORRADE_COMPARE(a.format(), PixelFormat::RGBA); CORRADE_COMPARE(a.type(), PixelType::UnsignedShort); CORRADE_COMPARE(a.size(), Vector2i(2, 1)); @@ -163,8 +187,15 @@ void ImageTest::setDataCompressed() { auto data = new char[8]; CompressedImage2D a{CompressedPixelFormat::RGBAS3tcDxt1, {4, 4}, Containers::Array{data, 8}}; auto data2 = new char[16]; - a.setData(CompressedPixelFormat::RGBAS3tcDxt3, {8, 4}, Containers::Array{data2, 16}); + a.setData( + #ifndef MAGNUM_TARGET_GLES + CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), + #endif + CompressedPixelFormat::RGBAS3tcDxt3, {8, 4}, Containers::Array{data2, 16}); + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{4}); + #endif CORRADE_COMPARE(a.format(), CompressedPixelFormat::RGBAS3tcDxt3); CORRADE_COMPARE(a.size(), Vector2i(8, 4)); CORRADE_COMPARE(a.data(), data2); @@ -173,9 +204,11 @@ void ImageTest::setDataCompressed() { void ImageTest::toReference() { auto data = new char[3]; - const Image2D a(PixelFormat::Red, PixelType::UnsignedByte, {1, 3}, data); + const Image2D a{PixelStorage{}.setAlignment(1), + PixelFormat::Red, PixelType::UnsignedByte, {1, 3}, data}; ImageView2D b = a; + CORRADE_COMPARE(b.storage().alignment(), 1); CORRADE_COMPARE(b.format(), PixelFormat::Red); CORRADE_COMPARE(b.type(), PixelType::UnsignedByte); CORRADE_COMPARE(b.size(), Vector2i(1, 3)); @@ -193,9 +226,16 @@ void ImageTest::toReference() { void ImageTest::toReferenceCommpressed() { auto data = new char[8]; - const CompressedImage2D a{CompressedPixelFormat::RGBAS3tcDxt1, {4, 4}, Containers::Array{data, 8}}; + const CompressedImage2D a{ + #ifndef MAGNUM_TARGET_GLES + CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), + #endif + CompressedPixelFormat::RGBAS3tcDxt1, {4, 4}, Containers::Array{data, 8}}; CompressedImageView2D b = a; + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE(b.storage().compressedBlockSize(), Vector3i{4}); + #endif CORRADE_COMPARE(b.format(), CompressedPixelFormat::RGBAS3tcDxt1); CORRADE_COMPARE(b.size(), Vector2i(4, 4)); CORRADE_COMPARE(b.data(), data); diff --git a/src/Magnum/Test/ImageViewTest.cpp b/src/Magnum/Test/ImageViewTest.cpp index e3bc71512..f42138c7f 100644 --- a/src/Magnum/Test/ImageViewTest.cpp +++ b/src/Magnum/Test/ImageViewTest.cpp @@ -50,8 +50,10 @@ ImageViewTest::ImageViewTest() { void ImageViewTest::construct() { const char data[3]{}; - ImageView2D a(PixelFormat::Red, PixelType::UnsignedByte, {1, 3}, data); + ImageView2D a{PixelStorage{}.setAlignment(1), + PixelFormat::Red, PixelType::UnsignedByte, {1, 3}, data}; + CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), PixelFormat::Red); CORRADE_COMPARE(a.type(), PixelType::UnsignedByte); CORRADE_COMPARE(a.size(), Vector2i(1, 3)); @@ -60,8 +62,15 @@ void ImageViewTest::construct() { void ImageViewTest::constructCompressed() { const char data[8]{}; - CompressedImageView2D a{CompressedPixelFormat::RGBAS3tcDxt1, {4, 4}, data}; - + CompressedImageView2D a{ + #ifndef MAGNUM_TARGET_GLES + CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), + #endif + CompressedPixelFormat::RGBAS3tcDxt1, {4, 4}, data}; + + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{4}); + #endif CORRADE_COMPARE(a.format(), CompressedPixelFormat::RGBAS3tcDxt1); CORRADE_COMPARE(a.size(), Vector2i(4, 4)); CORRADE_COMPARE(a.data(), data); @@ -69,10 +78,12 @@ void ImageViewTest::constructCompressed() { void ImageViewTest::setData() { const char data[3]{}; - ImageView2D a(PixelFormat::Red, PixelType::UnsignedByte, {1, 3}, data); + ImageView2D a{PixelStorage{}.setAlignment(1), + PixelFormat::Red, PixelType::UnsignedByte, {1, 3}, data}; const char data2[8]{}; a.setData(data2); + CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), PixelFormat::Red); CORRADE_COMPARE(a.type(), PixelType::UnsignedByte); CORRADE_COMPARE(a.size(), Vector2i(1, 3)); @@ -81,10 +92,17 @@ void ImageViewTest::setData() { void ImageViewTest::setDataCompressed() { const char data[8]{}; - CompressedImageView2D a{CompressedPixelFormat::RGBAS3tcDxt1, {4, 4}, data}; + CompressedImageView2D a{ + #ifndef MAGNUM_TARGET_GLES + CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), + #endif + CompressedPixelFormat::RGBAS3tcDxt1, {4, 4}, data}; const char data2[16]{}; a.setData(data2); + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{4}); + #endif CORRADE_COMPARE(a.format(), CompressedPixelFormat::RGBAS3tcDxt1); CORRADE_COMPARE(a.size(), Vector2i(4, 4)); CORRADE_COMPARE(a.data(), data2); diff --git a/src/Magnum/Trade/ImageData.cpp b/src/Magnum/Trade/ImageData.cpp index 18a121382..749369e2f 100644 --- a/src/Magnum/Trade/ImageData.cpp +++ b/src/Magnum/Trade/ImageData.cpp @@ -27,6 +27,11 @@ namespace Magnum { namespace Trade { +template PixelStorage ImageData::storage() const { + CORRADE_ASSERT(!_compressed, "Trade::ImageData::storage(): the image is compressed", {}); + return _storage; +} + template PixelFormat ImageData::format() const { CORRADE_ASSERT(!_compressed, "Trade::ImageData::format(): the image is compressed", {}); return _format; @@ -37,8 +42,15 @@ template PixelType ImageData::type() const { return _type; } +#ifndef MAGNUM_TARGET_GLES +template CompressedPixelStorage ImageData::compressedStorage() const { + CORRADE_ASSERT(_compressed, "Trade::ImageData::compressedStorage(): the image is not compressed", {}); + return _compressedStorage; +} +#endif + template CompressedPixelFormat ImageData::compressedFormat() const { - CORRADE_ASSERT(_compressed, "Trade::ImageData::format(): the image is not compressed", {}); + CORRADE_ASSERT(_compressed, "Trade::ImageData::compressedFormat(): the image is not compressed", {}); return _compressedFormat; } @@ -59,8 +71,8 @@ const & const #endif { - CORRADE_ASSERT(!_compressed, "Trade::ImageData::type(): the image is compressed", (ImageView{_format, _type, _size})); - return ImageView{_format, _type, _size, _data}; + CORRADE_ASSERT(!_compressed, "Trade::ImageData::type(): the image is compressed", (ImageView{_storage, _format, _type, _size})); + return ImageView{_storage, _format, _type, _size, _data}; } template ImageData::operator CompressedImageView() @@ -70,8 +82,16 @@ const & const #endif { + #ifndef MAGNUM_TARGET_GLES + CORRADE_ASSERT(_compressed, "Trade::ImageData::type(): the image is not compressed", (CompressedImageView{_compressedStorage, _compressedFormat, _size})); + #else CORRADE_ASSERT(_compressed, "Trade::ImageData::type(): the image is not compressed", (CompressedImageView{_compressedFormat, _size})); - return CompressedImageView{_compressedFormat, _size, _data}; + #endif + return CompressedImageView{ + #ifndef MAGNUM_TARGET_GLES + _compressedStorage, + #endif + _compressedFormat, _size, _data}; } #ifndef DOXYGEN_GENERATING_OUTPUT diff --git a/src/Magnum/Trade/ImageData.h b/src/Magnum/Trade/ImageData.h index c90058774..239e8544f 100644 --- a/src/Magnum/Trade/ImageData.h +++ b/src/Magnum/Trade/ImageData.h @@ -58,6 +58,7 @@ template class ImageData { /** * @brief Construct uncompressed image data + * @param storage Storage of pixel data * @param format Format of pixel data * @param type Data type of pixel data * @param size Image size @@ -66,18 +67,40 @@ template class ImageData { * Note that the image data are not copied on construction, but they * are deleted on class destruction. */ - explicit ImageData(PixelFormat format, PixelType type, const VectorTypeFor& size, void* data): _compressed{false}, _format{format}, _type{type}, _size{size}, _data{reinterpret_cast(data), dataSize(size)} {} + explicit ImageData(PixelStorage storage, PixelFormat format, PixelType type, const VectorTypeFor& size, void* data): _compressed{false}, _storage{storage}, _format{format}, _type{type}, _size{size}, _data{reinterpret_cast(data), dataSize(size)} {} + /** @overload + * Similar to the above, but uses default @ref PixelStorage parameters. + */ + explicit ImageData(PixelFormat format, PixelType type, const VectorTypeFor& size, void* data): ImageData{{}, format, type, size, data} {} + + #ifndef MAGNUM_TARGET_GLES /** * @brief Construct compressed image data - * @param format Format of compressed data + * @param storage Storage of compressed pixel data + * @param format Format of compressed pixel data * @param size Image size * @param data Image data * * Note that the image data are not copied on construction, but they * are deleted on class destruction. + * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} + * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and + * WebGL. */ - explicit ImageData(CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data): _compressed{true}, _compressedFormat{format}, _size{size}, _data{std::move(data)} {} + explicit ImageData(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data); + #endif + + /** + * @brief Construct compressed image data + * @param format Format of compressed pixel data + * @param size Image size + * @param data Image data + * + * Similar the above, but uses default @ref CompressedPixelStorage + * parameters (or the hardcoded ones in OpenGL ES and WebGL). + */ + explicit ImageData(CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data); /** @brief Copying is not allowed */ ImageData(const ImageData&) = delete; @@ -130,11 +153,19 @@ template class ImageData { /*implicit*/ operator CompressedImageView() const && = delete; #endif + /** + * @brief Storage of pixel data + * + * The image is expected to be uncompressed. + * @see @ref isCompressed(), @ref compressedStorage() + */ + PixelStorage storage() const; + /** * @brief Format of pixel data * * The image is expected to be uncompressed. - * @see @ref isCompressed() + * @see @ref isCompressed(), @ref compressedFormat() */ PixelFormat format() const; @@ -146,11 +177,24 @@ template class ImageData { */ PixelType type() const; + #ifndef MAGNUM_TARGET_GLES /** - * @brief Format of compressed data + * @brief Storage of compressed pixel data * * The image is expected to be compressed. - * @see @ref isCompressed() + * @see @ref isCompressed(), @ref storage()) + * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} + * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and + * WebGL. + */ + CompressedPixelStorage compressedStorage() const; + #endif + + /** + * @brief Format of compressed pixel data + * + * The image is expected to be compressed. + * @see @ref isCompressed(), @ref format() */ CompressedPixelFormat compressedFormat() const; @@ -205,6 +249,12 @@ template class ImageData { private: bool _compressed; + union { + PixelStorage _storage; + #ifndef MAGNUM_TARGET_GLES + CompressedPixelStorage _compressedStorage; + #endif + }; union { PixelFormat _format; CompressedPixelFormat _compressedFormat; @@ -223,9 +273,31 @@ typedef ImageData<2> ImageData2D; /** @brief Three-dimensional image */ typedef ImageData<3> ImageData3D; +template ImageData::ImageData( + #ifndef MAGNUM_TARGET_GLES + const CompressedPixelStorage storage, + #endif + const CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data): _compressed{true}, + #ifndef MAGNUM_TARGET_GLES + _compressedStorage{storage}, + #endif + _compressedFormat{format}, _size{size}, _data{std::move(data)} {} + +#ifndef MAGNUM_TARGET_GLES +template inline ImageData::ImageData(const CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data): ImageData{{}, format, size, std::move(data)} {} +#endif + template inline ImageData::ImageData(ImageData&& other) noexcept: _compressed{std::move(other._compressed)}, _type{std::move(other._type)}, _size{std::move(other._size)}, _data{std::move(other._data)} { - if(_compressed) _compressedFormat = std::move(other._compressedFormat); - else _format = std::move(other._format); + if(_compressed) { + #ifndef MAGNUM_TARGET_GLES + _compressedStorage = std::move(other._compressedStorage); + #endif + _compressedFormat = std::move(other._compressedFormat); + } + else { + _storage = std::move(other._storage); + _format = std::move(other._format); + } other._size = {}; other._data = nullptr; @@ -234,8 +306,16 @@ template inline ImageData::ImageData(ImageDa template inline ImageData& ImageData::operator=(ImageData&& other) noexcept { using std::swap; swap(_compressed, other._compressed); - if(_compressed) swap(_compressedFormat, other._compressedFormat); - else swap(_format, other._format); + if(_compressed) { + #ifndef MAGNUM_TARGET_GLES + swap(_compressedStorage, other._compressedStorage); + #endif + swap(_compressedFormat, other._compressedFormat); + } + else { + swap(_storage, other._storage); + swap(_format, other._format); + } swap(_type, other._type); swap(_size, other._size); swap(_data, other._data); diff --git a/src/Magnum/Trade/Test/ImageDataTest.cpp b/src/Magnum/Trade/Test/ImageDataTest.cpp index 40b5dd5c7..f31625a8b 100644 --- a/src/Magnum/Trade/Test/ImageDataTest.cpp +++ b/src/Magnum/Trade/Test/ImageDataTest.cpp @@ -61,9 +61,11 @@ ImageDataTest::ImageDataTest() { void ImageDataTest::construct() { auto data = new char[3]; - Trade::ImageData2D a(PixelFormat::Red, PixelType::UnsignedByte, {1, 3}, data); + Trade::ImageData2D a{PixelStorage{}.setAlignment(1), + PixelFormat::Red, PixelType::UnsignedByte, {1, 3}, data}; CORRADE_VERIFY(!a.isCompressed()); + CORRADE_COMPARE(a.storage().alignment(), 1); CORRADE_COMPARE(a.format(), PixelFormat::Red); CORRADE_COMPARE(a.type(), PixelType::UnsignedByte); CORRADE_COMPARE(a.size(), Vector2i(1, 3)); @@ -72,9 +74,16 @@ void ImageDataTest::construct() { void ImageDataTest::constructCompressed() { auto data = new char[8]; - Trade::ImageData2D a{CompressedPixelFormat::RGBAS3tcDxt1, {4, 4}, Containers::Array{data, 8}}; + Trade::ImageData2D a{ + #ifndef MAGNUM_TARGET_GLES + CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), + #endif + CompressedPixelFormat::RGBAS3tcDxt1, {4, 4}, Containers::Array{data, 8}}; CORRADE_VERIFY(a.isCompressed()); + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE(a.compressedStorage().compressedBlockSize(), Vector3i{4}); + #endif CORRADE_COMPARE(a.compressedFormat(), CompressedPixelFormat::RGBAS3tcDxt1); CORRADE_COMPARE(a.size(), Vector2i(4, 4)); CORRADE_COMPARE(a.data(), data); @@ -88,13 +97,15 @@ void ImageDataTest::constructCopy() { void ImageDataTest::constructMove() { auto data = new char[3]; - Trade::ImageData2D a(PixelFormat::Red, PixelType::UnsignedByte, {1, 3}, data); + Trade::ImageData2D a{PixelStorage{}.setAlignment(1), + PixelFormat::Red, PixelType::UnsignedByte, {1, 3}, data}; Trade::ImageData2D b(std::move(a)); CORRADE_COMPARE(a.data(), nullptr); CORRADE_COMPARE(a.size(), Vector2i()); CORRADE_VERIFY(!b.isCompressed()); + CORRADE_COMPARE(b.storage().alignment(), 1); CORRADE_COMPARE(b.format(), PixelFormat::Red); CORRADE_COMPARE(b.type(), PixelType::UnsignedByte); CORRADE_COMPARE(b.size(), Vector2i(1, 3)); @@ -108,6 +119,7 @@ void ImageDataTest::constructMove() { CORRADE_COMPARE(b.size(), Vector2i(2, 6)); CORRADE_VERIFY(!c.isCompressed()); + CORRADE_COMPARE(c.storage().alignment(), 1); CORRADE_COMPARE(c.format(), PixelFormat::Red); CORRADE_COMPARE(c.type(), PixelType::UnsignedByte); CORRADE_COMPARE(c.size(), Vector2i(1, 3)); @@ -116,13 +128,20 @@ void ImageDataTest::constructMove() { void ImageDataTest::constructMoveCompressed() { auto data = new char[8]; - Trade::ImageData2D a{CompressedPixelFormat::RGBAS3tcDxt1, {4, 4}, Containers::Array{data, 8}}; + Trade::ImageData2D a{ + #ifndef MAGNUM_TARGET_GLES + CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}), + #endif + CompressedPixelFormat::RGBAS3tcDxt1, {4, 4}, Containers::Array{data, 8}}; Trade::ImageData2D b{std::move(a)}; CORRADE_COMPARE(a.data(), nullptr); CORRADE_COMPARE(a.size(), Vector2i()); CORRADE_VERIFY(b.isCompressed()); + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE(b.compressedStorage().compressedBlockSize(), Vector3i{4}); + #endif CORRADE_COMPARE(b.compressedFormat(), CompressedPixelFormat::RGBAS3tcDxt1); CORRADE_COMPARE(b.size(), Vector2i(4, 4)); CORRADE_COMPARE(b.data(), data); @@ -137,6 +156,9 @@ void ImageDataTest::constructMoveCompressed() { CORRADE_COMPARE(b.size(), Vector2i(8, 4)); CORRADE_VERIFY(c.isCompressed()); + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE(c.compressedStorage().compressedBlockSize(), Vector3i{4}); + #endif CORRADE_COMPARE(c.compressedFormat(), CompressedPixelFormat::RGBAS3tcDxt1); CORRADE_COMPARE(c.size(), Vector2i(4, 4)); CORRADE_COMPARE(c.data(), data);