From d314634352f2fe2abbe71d774f6bac008f2211ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Fri, 4 Sep 2015 13:23:47 +0200 Subject: [PATCH] Pixel storage support, part 5: new data properties computation. Removed *Image::dataSize() and added *Image::dataProperties(), which returns all properties separately for better introspection. This function is now just an convenience alias to PixelStorage::dataProperties(), which takes into account proper alignment and all other storage properties. --- src/Magnum/AbstractFramebuffer.cpp | 8 +- src/Magnum/AbstractTexture.cpp | 33 ++--- src/Magnum/BufferImage.cpp | 4 +- src/Magnum/BufferImage.h | 35 ++++- src/Magnum/CubeMapTexture.cpp | 49 +++---- src/Magnum/Image.h | 33 +++-- src/Magnum/ImageView.h | 35 ++++- src/Magnum/PixelStorage.cpp | 50 +++++-- src/Magnum/PixelStorage.h | 125 ++++++++++++++--- src/Magnum/Test/BufferImageGLTest.cpp | 2 +- src/Magnum/Test/PixelStorageTest.cpp | 190 ++++++++++++++++++++++++-- src/Magnum/Trade/ImageData.cpp | 8 +- src/Magnum/Trade/ImageData.h | 20 +-- 13 files changed, 470 insertions(+), 122 deletions(-) diff --git a/src/Magnum/AbstractFramebuffer.cpp b/src/Magnum/AbstractFramebuffer.cpp index 50776618a..26ebdc712 100644 --- a/src/Magnum/AbstractFramebuffer.cpp +++ b/src/Magnum/AbstractFramebuffer.cpp @@ -280,10 +280,10 @@ AbstractFramebuffer& AbstractFramebuffer::clear(const FramebufferClearMask mask) void AbstractFramebuffer::read(const Range2Di& rectangle, Image2D& image) { bindInternal(FramebufferTarget::Read); - const std::size_t dataSize = image.dataSize(rectangle.size()); + const std::size_t dataSize = Implementation::imageDataSizeFor(image, rectangle.size()); char* const data = new char[dataSize]; (Context::current()->state().framebuffer->readImplementation)(rectangle, image.format(), image.type(), dataSize, data); - image.setData(image.format(), image.type(), rectangle.size(), data); + image.setData(image.storage(), image.format(), image.type(), rectangle.size(), data); } Image2D AbstractFramebuffer::read(const Range2Di& rectangle, Image2D&& image) { @@ -297,10 +297,10 @@ void AbstractFramebuffer::read(const Range2Di& rectangle, BufferImage2D& image, /* If the buffer doesn't have sufficient size, resize it */ /** @todo Explicitly reset also when buffer usage changes */ if(image.size() != rectangle.size()) - image.setData(image.format(), image.type(), rectangle.size(), nullptr, usage); + image.setData(image.storage(), image.format(), image.type(), rectangle.size(), nullptr, usage); image.buffer().bindInternal(Buffer::TargetHint::PixelPack); - (Context::current()->state().framebuffer->readImplementation)(rectangle, image.format(), image.type(), image.dataSize(rectangle.size()), nullptr); + (Context::current()->state().framebuffer->readImplementation)(rectangle, image.format(), image.type(), Implementation::imageDataSizeFor(image, rectangle.size()), nullptr); } BufferImage2D AbstractFramebuffer::read(const Range2Di& rectangle, BufferImage2D&& image, BufferUsage usage) { diff --git a/src/Magnum/AbstractTexture.cpp b/src/Magnum/AbstractTexture.cpp index 663099330..149268648 100644 --- a/src/Magnum/AbstractTexture.cpp +++ b/src/Magnum/AbstractTexture.cpp @@ -1494,12 +1494,12 @@ void AbstractTexture::invalidateSubImageImplementationARB(GLint level, const Vec #ifndef MAGNUM_TARGET_GLES template void AbstractTexture::image(GLint level, Image& image) { const Math::Vector size = DataHelper::imageSize(*this, level); - const std::size_t dataSize = image.dataSize(size); + const std::size_t dataSize = Implementation::imageDataSizeFor(image, size); char* data = new char[dataSize]; Buffer::unbindInternal(Buffer::TargetHint::PixelPack); (this->*Context::current()->state().texture->getImageImplementation)(level, image.format(), image.type(), dataSize, data); - image.setData(image.format(), image.type(), size, data); + image.setData(image.storage(), image.format(), image.type(), size, data); } template void MAGNUM_EXPORT AbstractTexture::image<1>(GLint, Image<1>&); @@ -1508,9 +1508,9 @@ template void MAGNUM_EXPORT AbstractTexture::image<3>(GLint, Image<3>&); template void AbstractTexture::image(GLint level, BufferImage& image, BufferUsage usage) { const Math::Vector size = DataHelper::imageSize(*this, level); - const std::size_t dataSize = image.dataSize(size); + const std::size_t dataSize = Implementation::imageDataSizeFor(image, size); if(image.size() != size) - image.setData(image.format(), image.type(), size, nullptr, usage); + image.setData(image.storage(), image.format(), image.type(), size, nullptr, usage); image.buffer().bindInternal(Buffer::TargetHint::PixelPack); (this->*Context::current()->state().texture->getImageImplementation)(level, image.format(), image.type(), dataSize, nullptr); @@ -1522,15 +1522,15 @@ template void MAGNUM_EXPORT AbstractTexture::image<3>(GLint, BufferImage<3>&, Bu template void AbstractTexture::compressedImage(const GLint level, CompressedImage& image) { const Math::Vector size = DataHelper::imageSize(*this, level); - GLint dataSize; - (this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &dataSize); + GLint textureDataSize; + (this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &textureDataSize); GLint format; (this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_INTERNAL_FORMAT, &format); - Containers::Array data{std::size_t(dataSize)}; + Containers::Array data{Implementation::compressedImageDataSizeFor(image, size, textureDataSize)}; Buffer::unbindInternal(Buffer::TargetHint::PixelPack); - (this->*Context::current()->state().texture->getCompressedImageImplementation)(level, dataSize, data); - image.setData(CompressedPixelFormat(format), size, std::move(data)); + (this->*Context::current()->state().texture->getCompressedImageImplementation)(level, data.size(), data); + image.setData(image.storage(), CompressedPixelFormat(format), size, std::move(data)); } template void MAGNUM_EXPORT AbstractTexture::compressedImage<1>(GLint, CompressedImage<1>&); @@ -1539,12 +1539,13 @@ template void MAGNUM_EXPORT AbstractTexture::compressedImage<3>(GLint, Compresse template void AbstractTexture::compressedImage(const GLint level, CompressedBufferImage& image, BufferUsage usage) { const Math::Vector size = DataHelper::imageSize(*this, level); - GLint dataSize; - (this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &dataSize); + GLint textureDataSize; + (this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &textureDataSize); + const std::size_t dataSize = Implementation::compressedImageDataSizeFor(image, size, textureDataSize); GLint format; (this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_INTERNAL_FORMAT, &format); - image.setData(CompressedPixelFormat(format), size, {nullptr, std::size_t(dataSize)}, usage); + image.setData(image.storage(), CompressedPixelFormat(format), size, {nullptr, dataSize}, usage); image.buffer().bindInternal(Buffer::TargetHint::PixelPack); (this->*Context::current()->state().texture->getCompressedImageImplementation)(level, dataSize, nullptr); } @@ -1559,12 +1560,12 @@ template void AbstractTexture::subImage(const GLint leve const Math::Vector size = range.size(); const Vector3i paddedOffset = Vector3i::pad(range.min()); const Vector3i paddedSize = Vector3i::pad(size, 1); - const std::size_t dataSize = image.dataSize(size); + const std::size_t dataSize = Implementation::imageDataSizeFor(image, size); char* data = new char[dataSize]; Buffer::unbindInternal(Buffer::TargetHint::PixelPack); glGetTextureSubImage(_id, level, paddedOffset.x(), paddedOffset.y(), paddedOffset.z(), paddedSize.x(), paddedSize.y(), paddedSize.z(), GLenum(image.format()), GLenum(image.type()), dataSize, data); - image.setData(image.format(), image.type(), size, data); + image.setData(image.storage(), image.format(), image.type(), size, data); } template void MAGNUM_EXPORT AbstractTexture::subImage<1>(GLint, const Range1Di&, Image<1>&); @@ -1575,11 +1576,11 @@ template void AbstractTexture::subImage(const GLint leve createIfNotAlready(); const Math::Vector size = range.size(); - const std::size_t dataSize = image.dataSize(size); + const std::size_t dataSize = Implementation::imageDataSizeFor(image, size); const Vector3i paddedOffset = Vector3i::pad(range.min()); const Vector3i paddedSize = Vector3i::pad(size, 1); if(image.size() != size) - image.setData(image.format(), image.type(), size, nullptr, usage); + image.setData(image.storage(), image.format(), image.type(), size, nullptr, usage); image.buffer().bindInternal(Buffer::TargetHint::PixelPack); glGetTextureSubImage(_id, level, paddedOffset.x(), paddedOffset.y(), paddedOffset.z(), paddedSize.x(), paddedSize.y(), paddedSize.z(), GLenum(image.format()), GLenum(image.type()), dataSize, nullptr); diff --git a/src/Magnum/BufferImage.cpp b/src/Magnum/BufferImage.cpp index fcc07bb59..e3a4c0b59 100644 --- a/src/Magnum/BufferImage.cpp +++ b/src/Magnum/BufferImage.cpp @@ -29,7 +29,7 @@ namespace Magnum { #ifndef MAGNUM_TARGET_GLES2 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); + _buffer.setData({data, Implementation::imageDataSizeFor(*this, size)}, usage); } template BufferImage::BufferImage(const PixelStorage storage, const PixelFormat format, const PixelType type): _storage{storage}, _format{format}, _type{type}, _buffer{Buffer::TargetHint::PixelPack} {} @@ -39,7 +39,7 @@ template void BufferImage::setData(const Pix _format = format; _type = type; _size = size; - _buffer.setData({data, dataSize(size)}, usage); + _buffer.setData({data, Implementation::imageDataSizeFor(*this, size)}, usage); } template CompressedBufferImage::CompressedBufferImage( diff --git a/src/Magnum/BufferImage.h b/src/Magnum/BufferImage.h index 30b86881f..7cc9f6b60 100644 --- a/src/Magnum/BufferImage.h +++ b/src/Magnum/BufferImage.h @@ -34,7 +34,7 @@ #include "Magnum/Buffer.h" #include "Magnum/DimensionTraits.h" #include "Magnum/PixelStorage.h" -#include "Magnum/Math/Vector3.h" +#include "Magnum/Math/Vector4.h" namespace Magnum { @@ -115,15 +115,23 @@ template class BufferImage { /** @brief Data type of pixel data */ PixelType type() const { return _type; } - /** @brief Pixel size (in bytes) */ - std::size_t pixelSize() const { return Implementation::imagePixelSize(_format, _type); } + /** + * @brief Pixel size (in bytes) + * + * @see @ref PixelStorage::pixelSize() + */ + std::size_t pixelSize() const { return PixelStorage::pixelSize(_format, _type); } /** @brief Image size */ VectorTypeFor size() const { return _size; } - /** @copydoc Image::dataSize() */ - std::size_t dataSize(const VectorTypeFor& size) const { - return Implementation::imageDataSize(_format, _type, size); + /** + * @brief Image data properties + * + * See @ref PixelStorage::dataProperties() for more information. + */ + std::tuple, std::size_t> dataProperties() const { + return Implementation::imageDataProperties(*this); } /** @brief Image buffer */ @@ -274,6 +282,21 @@ template class CompressedBufferImage { /** @brief Image size */ VectorTypeFor size() const { return _size; } + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Compressed image data properties + * + * See @ref CompressedPixelStorage::dataProperties() for more + * information. + * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} + * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and + * WebGL. + */ + std::tuple, std::size_t> dataProperties() const { + return Implementation::compressedImageDataProperties(*this); + } + #endif + /** @brief Image buffer */ Buffer& buffer() { return _buffer; } diff --git a/src/Magnum/CubeMapTexture.cpp b/src/Magnum/CubeMapTexture.cpp index 8c007b167..509071b30 100644 --- a/src/Magnum/CubeMapTexture.cpp +++ b/src/Magnum/CubeMapTexture.cpp @@ -60,11 +60,11 @@ void CubeMapTexture::image(const Int level, Image3D& image) { createIfNotAlready(); const Vector3i size{imageSize(level), 6}; - const std::size_t dataSize = image.dataSize(size); + const std::size_t dataSize = Implementation::imageDataSizeFor(image, size); char* data = new char[dataSize]; Buffer::unbindInternal(Buffer::TargetHint::PixelPack); glGetTextureImage(_id, level, GLenum(image.format()), GLenum(image.type()), dataSize, data); - image.setData(image.format(), image.type(), size, data); + image.setData(image.storage(), image.format(), image.type(), size, data); } Image3D CubeMapTexture::image(const Int level, Image3D&& image) { @@ -76,9 +76,9 @@ void CubeMapTexture::image(const Int level, BufferImage3D& image, const BufferUs createIfNotAlready(); const Vector3i size{imageSize(level), 6}; - const std::size_t dataSize = image.dataSize(size); + const std::size_t dataSize = Implementation::imageDataSizeFor(image, size); if(image.size() != size) - image.setData(image.format(), image.type(), size, nullptr, usage); + image.setData(image.storage(), image.format(), image.type(), size, nullptr, usage); image.buffer().bindInternal(Buffer::TargetHint::PixelPack); glGetTextureImage(_id, level, GLenum(image.format()), GLenum(image.type()), dataSize, nullptr); @@ -93,15 +93,16 @@ void CubeMapTexture::compressedImage(const Int level, CompressedImage3D& image) createIfNotAlready(); const Vector3i size{imageSize(level), 6}; - GLint dataSize; - (this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &dataSize); + GLint textureDataSize; + (this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &textureDataSize); + const std::size_t dataSize = Implementation::compressedImageDataSizeFor(image, size, textureDataSize); GLint format; (this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_INTERNAL_FORMAT, &format); - Containers::Array data{std::size_t(dataSize)}; + Containers::Array data{dataSize}; Buffer::unbindInternal(Buffer::TargetHint::PixelPack); glGetCompressedTextureImage(_id, level, dataSize, data); - image.setData(CompressedPixelFormat(format), size, std::move(data)); + image.setData(image.storage(), CompressedPixelFormat(format), size, std::move(data)); } CompressedImage3D CubeMapTexture::compressedImage(const Int level, CompressedImage3D&& image) { @@ -113,13 +114,14 @@ void CubeMapTexture::compressedImage(const Int level, CompressedBufferImage3D& i createIfNotAlready(); const Vector3i size{imageSize(level), 6}; - GLint dataSize; - (this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &dataSize); + GLint textureDataSize; + (this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &textureDataSize); + const std::size_t dataSize = Implementation::compressedImageDataSizeFor(image, size, textureDataSize); GLint format; (this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_INTERNAL_FORMAT, &format); image.buffer().bindInternal(Buffer::TargetHint::PixelPack); - image.setData(CompressedPixelFormat(format), size, {nullptr, std::size_t(dataSize)}, usage); + image.setData(image.storage(), CompressedPixelFormat(format), size, {nullptr, dataSize}, usage); glGetCompressedTextureImage(_id, level, dataSize, nullptr); } @@ -130,12 +132,12 @@ CompressedBufferImage3D CubeMapTexture::compressedImage(const Int level, Compres void CubeMapTexture::image(const Coordinate coordinate, const Int level, Image2D& image) { const Vector2i size = imageSize(level); - const std::size_t dataSize = image.dataSize(size); + const std::size_t dataSize = Implementation::imageDataSizeFor(image, size); char* data = new char[dataSize]; Buffer::unbindInternal(Buffer::TargetHint::PixelPack); (this->*Context::current()->state().texture->getCubeImageImplementation)(coordinate, level, size, image.format(), image.type(), dataSize, data); - image.setData(image.format(), image.type(), size, data); + image.setData(image.storage(), image.format(), image.type(), size, data); } Image2D CubeMapTexture::image(const Coordinate coordinate, const Int level, Image2D&& image) { @@ -145,9 +147,9 @@ Image2D CubeMapTexture::image(const Coordinate coordinate, const Int level, Imag void CubeMapTexture::image(const Coordinate coordinate, const Int level, BufferImage2D& image, const BufferUsage usage) { const Vector2i size = imageSize(level); - const std::size_t dataSize = image.dataSize(size); + const std::size_t dataSize = Implementation::imageDataSizeFor(image, size); if(image.size() != size) - image.setData(image.format(), image.type(), size, nullptr, usage); + image.setData(image.storage(), image.format(), image.type(), size, nullptr, usage); image.buffer().bindInternal(Buffer::TargetHint::PixelPack); (this->*Context::current()->state().texture->getCubeImageImplementation)(coordinate, level, size, image.format(), image.type(), dataSize, nullptr); @@ -160,15 +162,15 @@ BufferImage2D CubeMapTexture::image(const Coordinate coordinate, const Int level void CubeMapTexture::compressedImage(const Coordinate coordinate, const Int level, CompressedImage2D& image) { const Vector2i size = imageSize(level); - GLint dataSize; - (this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &dataSize); + GLint textureDataSize; + (this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &textureDataSize); GLint format; (this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_INTERNAL_FORMAT, &format); - Containers::Array data{std::size_t(dataSize)}; + Containers::Array data{Implementation::compressedImageDataSizeFor(image, size, textureDataSize)}; Buffer::unbindInternal(Buffer::TargetHint::PixelPack); - (this->*Context::current()->state().texture->getCompressedCubeImageImplementation)(coordinate, level, size, dataSize, data); - image.setData(CompressedPixelFormat(format), size, std::move(data)); + (this->*Context::current()->state().texture->getCompressedCubeImageImplementation)(coordinate, level, size, data.size(), data); + image.setData(image.storage(), CompressedPixelFormat(format), size, std::move(data)); } CompressedImage2D CubeMapTexture::compressedImage(const Coordinate coordinate, const Int level, CompressedImage2D&& image) { @@ -178,12 +180,13 @@ CompressedImage2D CubeMapTexture::compressedImage(const Coordinate coordinate, c void CubeMapTexture::compressedImage(const Coordinate coordinate, const Int level, CompressedBufferImage2D& image, const BufferUsage usage) { const Vector2i size = imageSize(level); - GLint dataSize; - (this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &dataSize); + GLint textureDataSize; + (this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &textureDataSize); + const std::size_t dataSize = Implementation::compressedImageDataSizeFor(image, size, textureDataSize); GLint format; (this->*Context::current()->state().texture->getLevelParameterivImplementation)(level, GL_TEXTURE_INTERNAL_FORMAT, &format); - image.setData(CompressedPixelFormat(format), size, {nullptr, std::size_t(dataSize)}, usage); + image.setData(image.storage(), CompressedPixelFormat(format), size, {nullptr, dataSize}, usage); image.buffer().bindInternal(Buffer::TargetHint::PixelPack); (this->*Context::current()->state().texture->getCompressedCubeImageImplementation)(coordinate, level, size, dataSize, nullptr); } diff --git a/src/Magnum/Image.h b/src/Magnum/Image.h index 0d5970ce2..6f7f2a1df 100644 --- a/src/Magnum/Image.h +++ b/src/Magnum/Image.h @@ -123,21 +123,23 @@ template class Image { /** @brief Data type of pixel data */ PixelType type() const { return _type; } - /** @brief Pixel size (in bytes) */ - std::size_t pixelSize() const { return Implementation::imagePixelSize(_format, _type); } + /** + * @brief Pixel size (in bytes) + * + * @see @ref PixelStorage::pixelSize() + */ + std::size_t pixelSize() const { return PixelStorage::pixelSize(_format, _type); } /** @brief Image size */ VectorTypeFor size() const { return _size; } /** - * @brief Size of data required to store image of given size + * @brief Image data properties * - * Takes color format, type and row alignment of this image into - * account. - * @see @ref pixelSize() + * See @ref PixelStorage::dataProperties() for more information. */ - std::size_t dataSize(const VectorTypeFor& size) const { - return Implementation::imageDataSize(_format, _type, size); + std::tuple, std::size_t> dataProperties() const { + return Implementation::imageDataProperties(*this); } /** @@ -310,6 +312,21 @@ template class CompressedImage { /** @brief Image size */ VectorTypeFor size() const { return _size; } + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Compressed image data properties + * + * See @ref CompressedPixelStorage::dataProperties() for more + * information. + * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} + * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and + * WebGL. + */ + std::tuple, std::size_t> dataProperties() const { + return Implementation::compressedImageDataProperties(*this); + } + #endif + /** @brief Raw data */ Containers::ArrayView data() { return _data; } diff --git a/src/Magnum/ImageView.h b/src/Magnum/ImageView.h index b44d31153..6e4e339d3 100644 --- a/src/Magnum/ImageView.h +++ b/src/Magnum/ImageView.h @@ -33,7 +33,7 @@ #include "Magnum/DimensionTraits.h" #include "Magnum/PixelStorage.h" -#include "Magnum/Math/Vector3.h" +#include "Magnum/Math/Vector4.h" namespace Magnum { @@ -100,15 +100,23 @@ template class ImageView { /** @brief Data type of pixel data */ PixelType type() const { return _type; } - /** @brief Pixel size (in bytes) */ - std::size_t pixelSize() const { return Implementation::imagePixelSize(_format, _type); } + /** + * @brief Pixel size (in bytes) + * + * @see @ref PixelStorage::pixelSize() + */ + std::size_t pixelSize() const { return PixelStorage::pixelSize(_format, _type); } /** @brief Image size */ constexpr VectorTypeFor size() const { return _size; } - /** @copydoc Image::dataSize() */ - std::size_t dataSize(const VectorTypeFor& size) const { - return Implementation::imageDataSize(*this, _format, _type, size); + /** + * @brief Image data properties + * + * See @ref PixelStorage::dataProperties() for more information. + */ + std::tuple, std::size_t> dataProperties() const { + return Implementation::imageDataProperties(*this); } /** @brief Pointer to raw data */ @@ -233,6 +241,21 @@ template class CompressedImageView { /** @brief Image size */ constexpr VectorTypeFor size() const { return _size; } + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Compressed image data properties + * + * See @ref CompressedPixelStorage::dataProperties() for more + * information. + * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} + * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and + * WebGL. + */ + std::tuple, std::size_t> dataProperties() const { + return Implementation::compressedImageDataProperties(*this); + } + #endif + /** @brief Raw data */ constexpr Containers::ArrayView data() const { return _data; } diff --git a/src/Magnum/PixelStorage.cpp b/src/Magnum/PixelStorage.cpp index 3c5e01795..9618fc368 100644 --- a/src/Magnum/PixelStorage.cpp +++ b/src/Magnum/PixelStorage.cpp @@ -28,11 +28,11 @@ #include #include "Magnum/PixelFormat.h" -#include "Magnum/Math/Vector.h" +#include "Magnum/Math/Vector4.h" -namespace Magnum { namespace Implementation { +namespace Magnum { -std::size_t imagePixelSize(PixelFormat format, PixelType type) { +std::size_t PixelStorage::pixelSize(PixelFormat format, PixelType type) { std::size_t size = 0; switch(type) { case PixelType::UnsignedByte: @@ -151,18 +151,40 @@ std::size_t imagePixelSize(PixelFormat format, PixelType type) { CORRADE_ASSERT_UNREACHABLE(); } -template std::size_t imageDataSize(const PixelFormat format, const PixelType type, Math::Vector size) { - /** @todo Code this properly when all @fn_gl{PixelStore} parameters are implemented */ - /* Row size, rounded to multiple of 4 bytes */ - const std::size_t rowSize = ((size[0]*imagePixelSize(format, type) + 3)/4)*4; +std::tuple, std::size_t> PixelStorage::dataProperties(const PixelFormat format, const PixelType type, const Vector3i& size) const { + const std::size_t pixelSize = PixelStorage::pixelSize(format, type); + const Math::Vector3 dataSize{ + std::size_t(((( + #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) + _rowLength ? _rowLength*pixelSize : + #endif + size[0]*pixelSize) + _alignment - 1)/_alignment)*_alignment), + #ifndef MAGNUM_TARGET_GLES2 + std::size_t(_imageHeight ? _imageHeight : size.y()), + #else + std::size_t(size.y()), + #endif + std::size_t(size.z())}; + const std::size_t offset = (Math::Vector3{pixelSize, dataSize.x(), dataSize.xy().product()}*Math::Vector3{_skip}).sum(); - /** @todo Can't this be done somewhat nicer? */ - size[0] = 1; - return rowSize*size.product(); + return std::make_tuple(offset, size.product() ? dataSize : Math::Vector3{}, pixelSize); } -template MAGNUM_EXPORT std::size_t imageDataSize<1>(PixelFormat, PixelType, Math::Vector<1, Int>); -template MAGNUM_EXPORT std::size_t imageDataSize<2>(PixelFormat, PixelType, Math::Vector<2, Int>); -template MAGNUM_EXPORT std::size_t imageDataSize<3>(PixelFormat, PixelType, Math::Vector<3, Int>); +#ifndef MAGNUM_TARGET_GLES +std::tuple, std::size_t> CompressedPixelStorage::dataProperties(const Vector3i& size) const { + CORRADE_ASSERT(_blockDataSize && _blockSize.product(), "CompressedPixelStorage::dataProperties(): expected non-zero storage parameters", {}); + + const Vector3i blockCount = (size + _blockSize - Vector3i{1})/_blockSize; + const Math::Vector3 dataSize{ + std::size_t(_rowLength ? (_rowLength + _blockSize.x() - 1)/_blockSize.x() : blockCount.x()), + std::size_t(_imageHeight ? (_imageHeight + _blockSize.y() - 1)/_blockSize.y() : blockCount.y()), + std::size_t(blockCount.z())}; + + const Vector3i skipBlockCount = (_skip + _blockSize - Vector3i{1})/_blockSize; + const std::size_t offset = (Math::Vector3{1, dataSize.x(), dataSize.xy().product()}*Math::Vector3{skipBlockCount}).sum()*_blockDataSize; -}} + return std::make_tuple(offset, size.product() ? dataSize : Math::Vector3{}, _blockDataSize); +} +#endif + +} diff --git a/src/Magnum/PixelStorage.h b/src/Magnum/PixelStorage.h index 065926712..1782ce796 100644 --- a/src/Magnum/PixelStorage.h +++ b/src/Magnum/PixelStorage.h @@ -30,6 +30,7 @@ */ #include +#include #include "Magnum/Magnum.h" #include "Magnum/visibility.h" @@ -37,12 +38,6 @@ namespace Magnum { -namespace Implementation { - std::size_t MAGNUM_EXPORT imagePixelSize(PixelFormat format, PixelType type); - - template std::size_t imageDataSize(PixelFormat format, PixelType type, Math::Vector size); -} - /** @brief Pixel storage parameters @@ -63,8 +58,15 @@ currently used pixel pack/unpack parameters to avoid unnecessary calls to @see @ref CompressedPixelStorage */ -class PixelStorage { +class MAGNUM_EXPORT PixelStorage { public: + /** + * @brief Pixel size for given format/type combination (in bytes) + * + * @see @ref dataProperties() + */ + static std::size_t pixelSize(PixelFormat format, PixelType type); + /** * @brief Default constructor * @@ -192,11 +194,23 @@ class PixelStorage { return *this; } + /** + * @brief Data properties for given parameters + * + * Returns byte offset, (row length, row count, layer count) and pixel + * size for image of given @p size with current pixel storage + * parameters, @p format and @p type. The offset reflects the @ref skip() + * parameter. Adding byte offset and product of the vector gives + * minimal byte count to store given data. + * @see @ref pixelSize() + */ + std::tuple, std::size_t> dataProperties(PixelFormat format, PixelType type, const Vector3i& size) const; + + #ifndef DOXYGEN_GENERATING_OUTPUT + protected: + #else private: - #ifndef MAGNUM_TARGET_GLES - bool _swapBytes; - #endif - Int _alignment; + #endif #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) Int _rowLength; #endif @@ -204,6 +218,12 @@ class PixelStorage { Int _imageHeight; #endif Vector3i _skip; + + private: + #ifndef MAGNUM_TARGET_GLES + bool _swapBytes; + #endif + Int _alignment; }; #ifndef MAGNUM_TARGET_GLES @@ -223,7 +243,7 @@ Includes all parameters from @ref PixelStorage, except for @ref swapBytes() and @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 { +class MAGNUM_EXPORT CompressedPixelStorage: public PixelStorage { public: /** * @brief Default constructor @@ -261,6 +281,19 @@ class CompressedPixelStorage: public PixelStorage { return *this; } + /** + * @brief Data properties for given parameters + * + * Returns byte offset, count of blocks in each dimension and block + * data size for image of given @p size with current pixel storage + * parameters. Adding byte offset and product of the vector multiplied + * with block data size gives minimal byte count to store given data. + * + * Expects @ref compressedBlockSize() and @ref compressedBlockDataSize() + * to be non-zero. + */ + std::tuple, std::size_t> dataProperties(const Vector3i& size) const; + /* Overloads to remove WTF-factor from method chaining order */ #ifndef DOXYGEN_GENERATING_OUTPUT CompressedPixelStorage& setRowLength(Int length) { @@ -291,17 +324,75 @@ class CompressedPixelStorage: public PixelStorage { #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} {} + _skip{0}, + #ifndef MAGNUM_TARGET_GLES + _swapBytes{false}, + #endif + _alignment{4} {} + +namespace Implementation { + /* Used in *Image::dataProperties() */ + template std::tuple, std::size_t> imageDataProperties(const T& image) { + std::size_t offset; + Math::Vector3 dataSize; + std::size_t pixelSize; + std::tie(offset, dataSize, pixelSize) = image.storage().dataProperties(image.format(), image.type(), Vector3i::pad(image.size(), 1)); + return std::make_tuple(offset, Math::Vector::pad(dataSize), pixelSize); + } + + #ifndef MAGNUM_TARGET_GLES2 + /* Used in Compressed*Image::dataProperties() */ + template std::tuple, std::size_t> compressedImageDataProperties(const T& image) { + std::size_t offset; + Math::Vector3 blockCount; + std::size_t blockSize; + std::tie(offset, blockCount, blockSize) = image.storage().dataProperties(Vector3i::pad(image.size(), 1)); + return std::make_tuple(offset, Math::Vector::pad(blockCount), blockSize); + } + #endif + + /* Used in image query functions */ + template std::size_t imageDataSizeFor(const T& image, const Math::Vector& size) { + const auto paddedSize = Vector3i::pad(size, 1); + + std::size_t offset; + Math::Vector3 dataSize; + std::size_t pixelSize; + std::tie(offset, dataSize, pixelSize) = image.storage().dataProperties(image.format(), image.type(), paddedSize); + + /* I would subtract also (dataSize.x() - pixelSize*paddedSize.x()) but NVidia + then complains that the buffer is too small */ + return offset + dataSize.product() - (dataSize.y() - paddedSize.y())*dataSize.x(); + } + + /* Used in data size assertions */ + template inline std::size_t imageDataSize(const T& image) { + return imageDataSizeFor(image, image.size()); + } + + #ifndef MAGNUM_TARGET_GLES + /* Used in image query functions */ + template std::size_t compressedImageDataSizeFor(const T& image, const Math::Vector& size, std::size_t dataSize) { + if(!image.storage().compressedBlockSize().product() || !image.storage().compressedBlockDataSize()) + return dataSize; + + std::size_t offset; + Math::Vector3 blockCount; + std::size_t blockDataSize; + std::tie(offset, blockCount, blockDataSize) = image.storage().dataProperties(Vector3i::pad(size, 1)); + + const auto realBlockCount = Math::Vector3{(Vector3i::pad(size, 1) + image.storage().compressedBlockSize() - Vector3i{1})/image.storage().compressedBlockSize()}; + + return offset + (blockCount.product() - (blockCount.x() - realBlockCount.x()) - (blockCount.y() - realBlockCount.y())*blockCount.x())*blockDataSize; + } + #endif +} } diff --git a/src/Magnum/Test/BufferImageGLTest.cpp b/src/Magnum/Test/BufferImageGLTest.cpp index 71a254af5..1aeb7629e 100644 --- a/src/Magnum/Test/BufferImageGLTest.cpp +++ b/src/Magnum/Test/BufferImageGLTest.cpp @@ -58,7 +58,7 @@ BufferImageGLTest::BufferImageGLTest() { } void BufferImageGLTest::construct() { - const char data[] = { 'a', 0, 0, 0, 'b', 0, 0, 0, 'c', 0, 0, 0 }; + const char data[] = { 'a', 'b', 'c' }; BufferImage2D a{PixelStorage{}.setAlignment(1), PixelFormat::Red, PixelType::UnsignedByte, {1, 3}, data, BufferUsage::StaticDraw}; diff --git a/src/Magnum/Test/PixelStorageTest.cpp b/src/Magnum/Test/PixelStorageTest.cpp index 1f56f4176..23ef72650 100644 --- a/src/Magnum/Test/PixelStorageTest.cpp +++ b/src/Magnum/Test/PixelStorageTest.cpp @@ -35,31 +35,195 @@ struct PixelStorageTest: TestSuite::Tester { explicit PixelStorageTest(); void pixelSize(); + + void dataProperties(); + void dataPropertiesAlignment(); + void dataPropertiesRowLength(); + #ifndef MAGNUM_TARGET_GLES2 + void dataPropertiesImageHeight(); + #endif + void dataSize(); + + #ifndef MAGNUM_TARGET_GLES + void dataPropertiesCompressed(); + void dataPropertiesCompressedRowLength(); + void dataPropertiesCompressedImageHeight(); + + void dataSizeCompressed(); + #endif }; +typedef Math::Vector3 Vector3st; + PixelStorageTest::PixelStorageTest() { addTests({&PixelStorageTest::pixelSize, - &PixelStorageTest::dataSize}); + + &PixelStorageTest::dataProperties, + &PixelStorageTest::dataPropertiesAlignment, + &PixelStorageTest::dataPropertiesRowLength, + #ifndef MAGNUM_TARGET_GLES2 + &PixelStorageTest::dataPropertiesImageHeight, + #endif + + &PixelStorageTest::dataSize, + + #ifndef MAGNUM_TARGET_GLES + &PixelStorageTest::dataPropertiesCompressed, + &PixelStorageTest::dataPropertiesCompressedRowLength, + &PixelStorageTest::dataPropertiesCompressedImageHeight, + + &PixelStorageTest::dataSizeCompressed + #endif + }); } void PixelStorageTest::pixelSize() { - CORRADE_COMPARE(Implementation::imagePixelSize(PixelFormat::RGBA, PixelType::UnsignedInt), 4*4); - CORRADE_COMPARE(Implementation::imagePixelSize(PixelFormat::DepthComponent, PixelType::UnsignedShort), 2); - CORRADE_COMPARE(Implementation::imagePixelSize(PixelFormat::StencilIndex, PixelType::UnsignedByte), 1); - CORRADE_COMPARE(Implementation::imagePixelSize(PixelFormat::DepthStencil, PixelType::UnsignedInt248), 4); + CORRADE_COMPARE(PixelStorage::pixelSize(PixelFormat::RGBA, PixelType::UnsignedInt), 4*4); + CORRADE_COMPARE(PixelStorage::pixelSize(PixelFormat::DepthComponent, PixelType::UnsignedShort), 2); + CORRADE_COMPARE(PixelStorage::pixelSize(PixelFormat::StencilIndex, PixelType::UnsignedByte), 1); + CORRADE_COMPARE(PixelStorage::pixelSize(PixelFormat::DepthStencil, PixelType::UnsignedInt248), 4); +} + +void PixelStorageTest::dataProperties() { + PixelStorage storage; + storage.setAlignment(1); + + CORRADE_COMPARE(storage.dataProperties(PixelFormat::RGBA, PixelType::UnsignedByte, Vector3i{0}), + (std::tuple{0, {0, 0, 0}, 4})); + CORRADE_COMPARE(storage.dataProperties(PixelFormat::RGBA, PixelType::UnsignedByte, Vector3i{1}), + (std::tuple{0, {4, 1, 1}, 4})); + CORRADE_COMPARE(storage.dataProperties(PixelFormat::Red, PixelType::UnsignedByte, {8, 2, 1}), + (std::tuple{0, {8, 2, 1}, 1})); + CORRADE_COMPARE(storage.dataProperties(PixelFormat::Red, PixelType::UnsignedByte, {2, 4, 1}), + (std::tuple{0, {2, 4, 1}, 1})); + CORRADE_COMPARE(storage.dataProperties(PixelFormat::Red, PixelType::UnsignedByte, {2, 4, 6}), + (std::tuple{0, {2, 4, 6}, 1})); +} + +void PixelStorageTest::dataPropertiesAlignment() { + PixelStorage storage; + storage.setAlignment(8) + .setSkip({3, 2, 1}); + + CORRADE_COMPARE(storage.dataProperties(PixelFormat::RGBA, PixelType::UnsignedByte, Vector3i{0}), + (std::tuple{3*4, {0, 0, 0}, 4})); + CORRADE_COMPARE(storage.dataProperties(PixelFormat::RGBA, PixelType::UnsignedByte, Vector3i{1}), + (std::tuple{8 + 16 + 3*4, {8, 1, 1}, 4})); + CORRADE_COMPARE(storage.dataProperties(PixelFormat::Red, PixelType::UnsignedByte, {8, 2, 1}), + (std::tuple{16 + 16 + 3, {8, 2, 1}, 1})); + CORRADE_COMPARE(storage.dataProperties(PixelFormat::Red, PixelType::UnsignedByte, {2, 4, 1}), + (std::tuple{32 + 16 + 3, {8, 4, 1}, 1})); + CORRADE_COMPARE(storage.dataProperties(PixelFormat::Red, PixelType::UnsignedByte, {2, 4, 6}), + (std::tuple{32 + 16 + 3, {8, 4, 6}, 1})); +} + +void PixelStorageTest::dataPropertiesRowLength() { + PixelStorage storage; + storage.setAlignment(4) + .setRowLength(15) + .setSkip({3, 7, 0}); + + CORRADE_COMPARE(storage.dataProperties(PixelFormat::RGBA, PixelType::UnsignedByte, Vector3i{0}), + (std::tuple{3*4 + 7*15*4, {0, 0, 0}, 4})); + CORRADE_COMPARE(storage.dataProperties(PixelFormat::RGBA, PixelType::UnsignedByte, Vector3i{1}), + (std::tuple{3*4 + 7*15*4, {60, 1, 1}, 4})); + CORRADE_COMPARE(storage.dataProperties(PixelFormat::Red, PixelType::UnsignedByte, {4, 2, 1}), + (std::tuple{3 + 7*16, {16, 2, 1}, 1})); + CORRADE_COMPARE(storage.dataProperties(PixelFormat::Red, PixelType::UnsignedByte, {2, 4, 1}), + (std::tuple{3 + 7*16, {16, 4, 1}, 1})); + CORRADE_COMPARE(storage.dataProperties(PixelFormat::Red, PixelType::UnsignedByte, {2, 4, 6}), + (std::tuple{3 + 7*16, {16, 4, 6}, 1})); } +#ifndef MAGNUM_TARGET_GLES2 +void PixelStorageTest::dataPropertiesImageHeight() { + PixelStorage storage; + storage.setAlignment(1) + .setImageHeight(128) + .setSkip({3, 7, 2}); + + CORRADE_COMPARE(storage.dataProperties(PixelFormat::RGBA, PixelType::UnsignedByte, Vector3i{0}), + (std::tuple{3*4, {0, 0, 0}, 4})); + CORRADE_COMPARE(storage.dataProperties(PixelFormat::RGBA, PixelType::UnsignedByte, Vector3i{1}), + (std::tuple{3*4 + 7*1*4 + 2*128*1*4, {4, 128, 1}, 4})); + CORRADE_COMPARE(storage.dataProperties(PixelFormat::Red, PixelType::UnsignedByte, {4, 2, 1}), + (std::tuple{3 + 7*1*4 + 2*128*4, {4, 128, 1}, 1})); + CORRADE_COMPARE(storage.dataProperties(PixelFormat::Red, PixelType::UnsignedByte, {2, 4, 1}), + (std::tuple{3 + 7*1*2 + 2*128*2, {2, 128, 1}, 1})); + CORRADE_COMPARE(storage.dataProperties(PixelFormat::Red, PixelType::UnsignedByte, {2, 4, 6}), + (std::tuple{3 + 7*1*2 + 2*128*2, {2, 128, 6}, 1})); +} +#endif + void PixelStorageTest::dataSize() { - /* Verify that row size is properly rounded */ - CORRADE_COMPARE(Image2D(PixelFormat::RGBA, PixelType::UnsignedByte).dataSize({}), 0); - CORRADE_COMPARE(Image2D(PixelFormat::Red, PixelType::UnsignedByte).dataSize({4, 2}), 8); - CORRADE_COMPARE(Image2D(PixelFormat::Red, PixelType::UnsignedByte).dataSize({2, 4}), 16); - CORRADE_COMPARE(Image2D(PixelFormat::RGBA, PixelType::UnsignedByte).dataSize(Vector2i(1)), 4); - - CORRADE_COMPARE(Image2D(PixelFormat::RGBA, PixelType::UnsignedShort).dataSize({16, 8}), - 4*2*16*8); + /* The same parameters as in PixelStorageGLTest 3D case */ + const Image2D image{PixelStorage{}.setAlignment(2) + .setRowLength(3) + #ifndef MAGNUM_TARGET_GLES2 + .setImageHeight(5) + #endif + .setSkip({2, 3, 1}), + PixelFormat::RGB, PixelType::UnsignedByte}; + + #ifndef MAGNUM_TARGET_GLES2 + CORRADE_COMPARE(Implementation::imageDataSizeFor(image, Vector2i{2, 3}), + 5*10 + 3*10 + 6 + 3*10); + #else + CORRADE_COMPARE(Implementation::imageDataSizeFor(image, Vector2i{2, 3}), + 3*10 + 3*10 + 6 + 3*10); + #endif +} + +#ifndef MAGNUM_TARGET_GLES +void PixelStorageTest::dataPropertiesCompressed() { + CompressedPixelStorage storage; + storage.setCompressedBlockSize({3, 4, 5}) + .setCompressedBlockDataSize(16); + + CORRADE_COMPARE(storage.dataProperties({2, 8, 11}), + (std::tuple{0, {1, 2, 3}, 16})); +} + +void PixelStorageTest::dataPropertiesCompressedRowLength() { + CompressedPixelStorage storage; + storage.setCompressedBlockSize({3, 4, 5}) + .setCompressedBlockDataSize(9) + .setRowLength(12) + .setSkip({5, 8, 0}); + + CORRADE_COMPARE(storage.dataProperties({2, 8, 11}), + (std::tuple{(2 + 8)*9, {4, 2, 3}, 9})); +} + +void PixelStorageTest::dataPropertiesCompressedImageHeight() { + CompressedPixelStorage storage; + storage.setCompressedBlockSize({3, 4, 5}) + .setCompressedBlockDataSize(16) + .setImageHeight(12) + .setSkip({5, 8, 11}); + + CORRADE_COMPARE(storage.dataProperties({2, 8, 11}), + (std::tuple{(2 + 2 + 9)*16, {1, 3, 3}, 16})); +} + +void PixelStorageTest::dataSizeCompressed() { + /* Tf the storage doesn't contain any info about block sizes (the default, + using the provided value */ + CORRADE_COMPARE(Implementation::compressedImageDataSizeFor(CompressedImage3D{}, + Vector2i{37, 35}, 1579), 1579); + + /* The same parameters as in PixelStorageGLTest 3D case */ + const CompressedImage3D image{CompressedPixelStorage{} + .setCompressedBlockSize({4, 4, 1}) + .setCompressedBlockDataSize(16) + .setRowLength(8) + .setImageHeight(8) + .setSkip({4, 4, 4})}; + CORRADE_COMPARE(Implementation::compressedImageDataSizeFor(image, Vector3i{4, 4, 1}, 1579), + 16*4*4 + 16*4); } +#endif }} diff --git a/src/Magnum/Trade/ImageData.cpp b/src/Magnum/Trade/ImageData.cpp index 749369e2f..83ec7c179 100644 --- a/src/Magnum/Trade/ImageData.cpp +++ b/src/Magnum/Trade/ImageData.cpp @@ -56,12 +56,12 @@ template CompressedPixelFormat ImageData::co template std::size_t ImageData::pixelSize() const { CORRADE_ASSERT(!_compressed, "Trade::ImageData::pixelSize(): the image is compressed", {}); - return Implementation::imagePixelSize(_format, _type); + return PixelStorage::pixelSize(_format, _type); } -template std::size_t ImageData::dataSize(const VectorTypeFor< dimensions, Int >& size) const { - CORRADE_ASSERT(!_compressed, "Trade::ImageData::dataSize(): the image is compressed", {}); - return Implementation::imageDataSize(_format, _type, size); +template std::tuple, std::size_t> ImageData::dataProperties() const { + CORRADE_ASSERT(!_compressed, "Trade::ImageData::dataProperties(): the image is compressed", {}); + return Implementation::imageDataProperties(*this); } template ImageData::operator ImageView() diff --git a/src/Magnum/Trade/ImageData.h b/src/Magnum/Trade/ImageData.h index bf59087b9..fcf842d7a 100644 --- a/src/Magnum/Trade/ImageData.h +++ b/src/Magnum/Trade/ImageData.h @@ -41,7 +41,7 @@ namespace Magnum { namespace Trade { Access to either uncompressed or compressed image data provided by @ref AbstractImporter subclasses, the compression state is distinguished with @ref isCompressed(). Uncompressed images have @ref format(), @ref type(), -@ref pixelSize() and @ref dataSize() properties and are convertible to +@ref pixelSize() and @ref dataProperties() properties and are convertible to @ref ImageView. Compressed images have just the @ref compressedFormat() property and are convertible to @ref CompressedImageView. @@ -67,7 +67,7 @@ template class ImageData { * Note that the image data are not copied on construction, but they * are deleted on class destruction. */ - 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)} {} + 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), Implementation::imageDataSizeFor(*this, size)} {} /** @overload * Similar to the above, but uses default @ref PixelStorage parameters. @@ -202,7 +202,7 @@ template class ImageData { * @brief Pixel size (in bytes) * * The image is expected to be uncompressed. - * @see @ref isCompressed() + * @see @ref isCompressed(), @ref PixelStorage::pixelSize() */ std::size_t pixelSize() const; @@ -210,13 +210,17 @@ template class ImageData { VectorTypeFor size() const { return _size; } /** - * @brief Size of data required to store uncompressed image of given size + * @brief Uncompressed image data properties * - * The image is expected to be uncompressed. Takes color format, type - * and row alignment of this image into account. - * @see @ref isCompressed(), @ref pixelSize() + * The image is expected to be uncompressed. See + * @ref PixelStorage::dataProperties() for more information. + * @see @ref isCompressed() */ - std::size_t dataSize(const VectorTypeFor& size) const; + std::tuple, std::size_t> dataProperties() const; + + /* compressed data properties are not available because the importers + are not setting any block size pixel storage properties to avoid + needless state changes -- thus the calculation can't be done */ /** @brief Raw data */ Containers::ArrayView data() { return _data; }