Browse Source

Pixel storage support, part 4: the PixelStorage class.

Just created, documented and used the class in images, nothing is used
anywhere yet.
pull/107/head
Vladimír Vondruš 11 years ago
parent
commit
413908badc
  1. 38
      src/Magnum/BufferImage.cpp
  2. 133
      src/Magnum/BufferImage.h
  3. 13
      src/Magnum/Image.cpp
  4. 166
      src/Magnum/Image.h
  5. 102
      src/Magnum/ImageView.h
  6. 5
      src/Magnum/Magnum.h
  7. 263
      src/Magnum/PixelStorage.h
  8. 46
      src/Magnum/Test/BufferImageGLTest.cpp
  9. 56
      src/Magnum/Test/ImageTest.cpp
  10. 28
      src/Magnum/Test/ImageViewTest.cpp
  11. 28
      src/Magnum/Trade/ImageData.cpp
  12. 100
      src/Magnum/Trade/ImageData.h
  13. 30
      src/Magnum/Trade/Test/ImageDataTest.cpp

38
src/Magnum/BufferImage.cpp

@ -28,26 +28,52 @@
namespace Magnum {
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> BufferImage<dimensions>::BufferImage(PixelFormat format, PixelType type, const VectorTypeFor<dimensions, Int>& size, const void* data, BufferUsage usage): _format{format}, _type{type}, _size{size}, _buffer{Buffer::TargetHint::PixelPack} {
template<UnsignedInt dimensions> BufferImage<dimensions>::BufferImage(const PixelStorage storage, const PixelFormat format, const PixelType type, const VectorTypeFor<dimensions, Int>& 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<UnsignedInt dimensions> BufferImage<dimensions>::BufferImage(PixelFormat format, PixelType type): _format{format}, _type{type}, _buffer{Buffer::TargetHint::PixelPack} {}
template<UnsignedInt dimensions> BufferImage<dimensions>::BufferImage(const PixelStorage storage, const PixelFormat format, const PixelType type): _storage{storage}, _format{format}, _type{type}, _buffer{Buffer::TargetHint::PixelPack} {}
template<UnsignedInt dimensions> void BufferImage<dimensions>::setData(PixelFormat format, PixelType type, const VectorTypeFor<dimensions, Int>& size, const void* data, BufferUsage usage) {
template<UnsignedInt dimensions> void BufferImage<dimensions>::setData(const PixelStorage storage, const PixelFormat format, const PixelType type, const VectorTypeFor<dimensions, Int>& size, const void* const data, const BufferUsage usage) {
_storage = storage;
_format = format;
_type = type;
_size = size;
_buffer.setData({data, dataSize(size)}, usage);
}
template<UnsignedInt dimensions> CompressedBufferImage<dimensions>::CompressedBufferImage(CompressedPixelFormat format, const VectorTypeFor<dimensions, Int>& size, Containers::ArrayView<const void> data, BufferUsage usage): _format{format}, _size{size}, _buffer{Buffer::TargetHint::PixelPack}, _dataSize{data.size()} {
template<UnsignedInt dimensions> CompressedBufferImage<dimensions>::CompressedBufferImage(
#ifndef MAGNUM_TARGET_GLES
const CompressedPixelStorage storage,
#endif
const CompressedPixelFormat format, const VectorTypeFor<dimensions, Int>& size, const Containers::ArrayView<const void> 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<UnsignedInt dimensions> CompressedBufferImage<dimensions>::CompressedBufferImage(): _format{}, _buffer{Buffer::TargetHint::PixelPack}, _dataSize{} {}
template<UnsignedInt dimensions> CompressedBufferImage<dimensions>::CompressedBufferImage(
#ifndef MAGNUM_TARGET_GLES
const CompressedPixelStorage storage
#endif
):
#ifndef MAGNUM_TARGET_GLES
_storage{storage},
#endif
_format{}, _buffer{Buffer::TargetHint::PixelPack}, _dataSize{} {}
template<UnsignedInt dimensions> void CompressedBufferImage<dimensions>::setData(CompressedPixelFormat format, const VectorTypeFor<dimensions, Int>& size, Containers::ArrayView<const void> data, BufferUsage usage) {
template<UnsignedInt dimensions> void CompressedBufferImage<dimensions>::setData(
#ifndef MAGNUM_TARGET_GLES
const CompressedPixelStorage storage,
#endif
const CompressedPixelFormat format, const VectorTypeFor<dimensions, Int>& size, const Containers::ArrayView<const void> data, const BufferUsage usage)
{
#ifndef MAGNUM_TARGET_GLES
_storage = storage;
#endif
_format = format;
_size = size;
_buffer.setData(data, usage);

133
src/Magnum/BufferImage.h

@ -57,6 +57,7 @@ template<UnsignedInt dimensions> 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<UnsignedInt dimensions> class BufferImage {
* @todo Make it more flexible (usable with
* @extension{ARB,buffer_storage}, avoiding relocations...)
*/
explicit BufferImage(PixelFormat format, PixelType type, const VectorTypeFor<dimensions, Int>& size, const void* data, BufferUsage usage);
explicit BufferImage(PixelStorage storage, PixelFormat format, PixelType type, const VectorTypeFor<dimensions, Int>& 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<dimensions, Int>& 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<dimensions>&) = delete;
@ -91,6 +106,9 @@ template<UnsignedInt dimensions> class BufferImage {
/** @brief Move assignment */
BufferImage<dimensions>& operator=(BufferImage<dimensions>&& 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<UnsignedInt dimensions> 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<UnsignedInt dimensions> class BufferImage {
* @todo Make it more flexible (usable with
* @extension{ARB,buffer_storage}, avoiding relocations...)
*/
void setData(PixelFormat format, PixelType type, const VectorTypeFor<dimensions, Int>& size, const void* data, BufferUsage usage);
void setData(PixelStorage storage, PixelFormat format, PixelType type, const VectorTypeFor<dimensions, Int>& 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<dimensions, Int>& size, const void* data, BufferUsage usage) {
setData({}, format, type, size, data, usage);
}
private:
PixelStorage _storage;
PixelFormat _format;
PixelType _type;
Math::Vector<Dimensions, Int> _size;
@ -161,9 +188,11 @@ template<UnsignedInt dimensions> 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<UnsignedInt dimensions> 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<dimensions, Int>& size, Containers::ArrayView<const void> 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<dimensions, Int>& size, Containers::ArrayView<const void> 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<UnsignedInt dimensions> class CompressedBufferImage {
/** @brief Move assignment */
CompressedBufferImage<dimensions>& operator=(CompressedBufferImage<dimensions>&& 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<UnsignedInt dimensions> 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<UnsignedInt dimensions> 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<dimensions, Int>& size, Containers::ArrayView<const void> 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<dimensions, Int>& size, Containers::ArrayView<const void> data, BufferUsage usage);
private:
#ifndef MAGNUM_TARGET_GLES
CompressedPixelStorage _storage;
#endif
CompressedPixelFormat _format;
Math::Vector<Dimensions, Int> _size;
Buffer _buffer;
@ -237,17 +332,22 @@ typedef CompressedBufferImage<2> CompressedBufferImage2D;
/** @brief Three-dimensional compressed buffer image */
typedef CompressedBufferImage<3> CompressedBufferImage3D;
template<UnsignedInt dimensions> inline BufferImage<dimensions>::BufferImage(BufferImage<dimensions>&& other) noexcept: _format{std::move(other._format)}, _type{std::move(other._type)}, _size{std::move(other._size)}, _buffer{std::move(other._buffer)} {
template<UnsignedInt dimensions> inline BufferImage<dimensions>::BufferImage(BufferImage<dimensions>&& 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<UnsignedInt dimensions> inline CompressedBufferImage<dimensions>::CompressedBufferImage(CompressedBufferImage<dimensions>&& other) noexcept: _format{std::move(other._format)}, _size{std::move(other._size)}, _buffer{std::move(other._buffer)}, _dataSize{std::move(other._dataSize)} {
template<UnsignedInt dimensions> inline CompressedBufferImage<dimensions>::CompressedBufferImage(CompressedBufferImage<dimensions>&& 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<UnsignedInt dimensions> inline BufferImage<dimensions>& BufferImage<dimensions>::operator=(BufferImage<dimensions>&& 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<UnsignedInt dimensions> inline BufferImage<dimensions>& BufferImage<dim
template<UnsignedInt dimensions> inline CompressedBufferImage<dimensions>& CompressedBufferImage<dimensions>::operator=(CompressedBufferImage<dimensions>&& 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<UnsignedInt dimensions> inline CompressedBufferImage<dimensions>::CompressedBufferImage(const CompressedPixelFormat format, const VectorTypeFor<dimensions, Int>& size, const Containers::ArrayView<const void> data, const BufferUsage usage): CompressedBufferImage{{}, format, size, data, usage} {}
template<UnsignedInt dimensions> inline CompressedBufferImage<dimensions>::CompressedBufferImage(): CompressedBufferImage{CompressedPixelStorage{}} {}
template<UnsignedInt dimensions> inline void CompressedBufferImage<dimensions>::setData(const CompressedPixelFormat format, const VectorTypeFor<dimensions, Int>& size, const Containers::ArrayView<const void> data, const BufferUsage usage) {
setData({}, format, size, data, usage);
}
#endif
#else
#error this header is not available in OpenGL ES 2.0 build
#endif

13
src/Magnum/Image.cpp

@ -27,15 +27,24 @@
namespace Magnum {
template<UnsignedInt dimensions> void Image<dimensions>::setData(PixelFormat format, PixelType type, const VectorTypeFor<dimensions, Int>& size, void* data) {
template<UnsignedInt dimensions> void Image<dimensions>::setData(PixelStorage storage, PixelFormat format, PixelType type, const VectorTypeFor<dimensions, Int>& size, void* data) {
delete[] _data;
_storage = storage;
_format = format;
_type = type;
_size = size;
_data = reinterpret_cast<char*>(data);
}
template<UnsignedInt dimensions> void CompressedImage<dimensions>::setData(CompressedPixelFormat format, const VectorTypeFor<dimensions, Int>& size, Containers::Array<char>&& data) {
template<UnsignedInt dimensions> void CompressedImage<dimensions>::setData(
#ifndef MAGNUM_TARGET_GLES
CompressedPixelStorage storage,
#endif
CompressedPixelFormat format, const VectorTypeFor<dimensions, Int>& size, Containers::Array<char>&& data)
{
#ifndef MAGNUM_TARGET_GLES
_storage = storage;
#endif
_format = format;
_size = size;
_data = std::move(data);

166
src/Magnum/Image.h

@ -50,6 +50,7 @@ template<UnsignedInt dimensions> 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<UnsignedInt dimensions> 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<dimensions, Int>& size, void* data): _format{format}, _type{type}, _size{size}, _data{reinterpret_cast<char*>(data)} {}
explicit Image(PixelStorage storage, PixelFormat format, PixelType type, const VectorTypeFor<dimensions, Int>& size, void* data): _storage{storage}, _format{format}, _type{type}, _size{size}, _data{reinterpret_cast<char*>(data)} {}
/** @overload
* Similar to the above, but uses default @ref PixelStorage parameters.
*/
explicit Image(PixelFormat format, PixelType type, const VectorTypeFor<dimensions, Int>& 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<dimensions>&) = delete;
@ -98,6 +114,9 @@ template<UnsignedInt dimensions> class Image {
/*implicit*/ operator ImageView<dimensions>() 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<UnsignedInt dimensions> 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<UnsignedInt dimensions> class Image {
* data are not copied, but they are deleted on destruction.
* @see @ref release()
*/
void setData(PixelFormat format, PixelType type, const VectorTypeFor<dimensions, Int>& size, void* data);
void setData(PixelStorage storage, PixelFormat format, PixelType type, const VectorTypeFor<dimensions, Int>& size, void* data);
/** @overload
* Similar to the above, but uses default @ref PixelStorage parameters.
*/
void setData(PixelFormat format, PixelType type, const VectorTypeFor<dimensions, Int>& size, void* data) {
setData({}, format, type, size, data);
}
/**
* @brief Release data storage
@ -158,6 +185,7 @@ template<UnsignedInt dimensions> class Image {
char* release();
private:
PixelStorage _storage;
PixelFormat _format;
PixelType _type;
Math::Vector<Dimensions, Int> _size;
@ -188,21 +216,57 @@ template<UnsignedInt dimensions> 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<dimensions, Int>& size, Containers::Array<char>&& 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<dimensions, Int>& size, Containers::Array<char>&& data): _format{format}, _size{size}, _data{std::move(data)} {}
explicit CompressedImage(CompressedPixelFormat format, const VectorTypeFor<dimensions, Int>& size, Containers::Array<char>&& 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<dimensions>&) = delete;
@ -229,7 +293,18 @@ template<UnsignedInt dimensions> class CompressedImage {
/*implicit*/ operator CompressedImageView<dimensions>() 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<UnsignedInt dimensions> class CompressedImage {
return reinterpret_cast<const T*>(_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<dimensions, Int>& size, Containers::Array<char>&& 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<dimensions, Int>& size, Containers::Array<char>&& data);
@ -277,6 +369,9 @@ template<UnsignedInt dimensions> class CompressedImage {
Containers::Array<char> release();
private:
#ifndef MAGNUM_TARGET_GLES
CompressedPixelStorage _storage;
#endif
CompressedPixelFormat _format;
Math::Vector<Dimensions, Int> _size;
Containers::Array<char> _data;
@ -291,18 +386,24 @@ typedef CompressedImage<2> CompressedImage2D;
/** @brief Three-dimensional compressed image */
typedef CompressedImage<3> CompressedImage3D;
template<UnsignedInt dimensions> inline Image<dimensions>::Image(Image<dimensions>&& other) noexcept: _format{std::move(other._format)}, _type{std::move(other._type)}, _size{std::move(other._size)}, _data{std::move(other._data)} {
template<UnsignedInt dimensions> inline Image<dimensions>::Image(Image<dimensions>&& 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<UnsignedInt dimensions> inline CompressedImage<dimensions>::CompressedImage(CompressedImage<dimensions>&& other) noexcept: _format{std::move(other._format)}, _size{std::move(other._size)}, _data{std::move(other._data)} {
template<UnsignedInt dimensions> inline CompressedImage<dimensions>::CompressedImage(CompressedImage<dimensions>&& 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<UnsignedInt dimensions> inline Image<dimensions>& Image<dimensions>::operator=(Image<dimensions>&& 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<UnsignedInt dimensions> inline Image<dimensions>& Image<dimensions>::op
template<UnsignedInt dimensions> inline CompressedImage<dimensions>& CompressedImage<dimensions>::operator=(CompressedImage<dimensions>&& 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<dimensions>{_format, _type, _size, _data};
return ImageView<dimensions>{_storage, _format, _type, _size, _data};
}
template<UnsignedInt dimensions> inline CompressedImage<dimensions>::operator CompressedImageView<dimensions>()
@ -335,7 +439,11 @@ const &
const
#endif
{
return CompressedImageView<dimensions>{_format, _size, _data};
return CompressedImageView<dimensions>{
#ifndef MAGNUM_TARGET_GLES
_storage,
#endif
_format, _size, _data};
}
template<UnsignedInt dimensions> inline char* Image<dimensions>::release() {
@ -354,6 +462,36 @@ template<UnsignedInt dimensions> inline Containers::Array<char> CompressedImage<
return data;
}
template<UnsignedInt dimensions> inline CompressedImage<dimensions>::CompressedImage(
#ifndef MAGNUM_TARGET_GLES
const CompressedPixelStorage storage,
#endif
const CompressedPixelFormat format, const VectorTypeFor<dimensions, Int>& size, Containers::Array<char>&& data):
#ifndef MAGNUM_TARGET_GLES
_storage{storage},
#endif
_format{format}, _size{size}, _data{std::move(data)} {}
template<UnsignedInt dimensions> inline CompressedImage<dimensions>::CompressedImage(
#ifndef MAGNUM_TARGET_GLES
const CompressedPixelStorage storage
#endif
)
#ifndef MAGNUM_TARGET_GLES
: _storage{storage}
#endif
{}
#ifndef MAGNUM_TARGET_GLES
template<UnsignedInt dimensions> inline CompressedImage<dimensions>::CompressedImage(const CompressedPixelFormat format, const VectorTypeFor<dimensions, Int>& size, Containers::Array<char>&& data): CompressedImage{{}, format, size, std::move(data)} {}
template<UnsignedInt dimensions> inline CompressedImage<dimensions>::CompressedImage(): CompressedImage{CompressedPixelStorage{}} {}
template<UnsignedInt dimensions> inline void CompressedImage<dimensions>::setData(const CompressedPixelFormat format, const VectorTypeFor<dimensions, Int>& size, Containers::Array<char>&& data) {
setData({}, format, size, std::move(data));
}
#endif
}
#endif

102
src/Magnum/ImageView.h

@ -61,15 +61,22 @@ template<UnsignedInt dimensions> 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<dimensions, Int>& size, const void* data): _format{format}, _type{type}, _size{size}, _data{reinterpret_cast<const char*>(data)} {}
constexpr explicit ImageView(PixelStorage storage, PixelFormat format, PixelType type, const VectorTypeFor<dimensions, Int>& size, const void* data) noexcept: _storage{storage}, _format{format}, _type{type}, _size{size}, _data{reinterpret_cast<const char*>(data)} {}
/** @overload
* Similar to the above, but uses default @ref PixelStorage parameters.
*/
constexpr explicit ImageView(PixelFormat format, PixelType type, const VectorTypeFor<dimensions, Int>& 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<UnsignedInt dimensions> 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<dimensions, Int>& size): _format{format}, _type{type}, _size{size}, _data{nullptr} {}
constexpr explicit ImageView(PixelStorage storage, PixelFormat format, PixelType type, const VectorTypeFor<dimensions, Int>& 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<dimensions, Int>& 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<UnsignedInt dimensions> class ImageView {
}
private:
PixelStorage _storage;
PixelFormat _format;
PixelType _type;
Math::Vector<Dimensions, Int> _size;
@ -148,23 +164,68 @@ template<UnsignedInt dimensions> 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<dimensions, Int>& size, Containers::ArrayView<const void> 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<dimensions, Int>& size, Containers::ArrayView<const void> data): _format{format}, _size{size}, _data{reinterpret_cast<const char*>(data.data()), data.size()} {}
constexpr explicit CompressedImageView(CompressedPixelFormat format, const VectorTypeFor<dimensions, Int>& size, Containers::ArrayView<const void> 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<dimensions, Int>& size): _format{format}, _size{size} {}
constexpr explicit CompressedImageView(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor<dimensions, Int>& 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<dimensions, Int>& 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<UnsignedInt dimensions> class CompressedImageView {
}
private:
#ifndef MAGNUM_TARGET_GLES
CompressedPixelStorage _storage;
#endif
CompressedPixelFormat _format;
Math::Vector<Dimensions, Int> _size;
Containers::ArrayView<const char> _data;
@ -207,6 +271,32 @@ typedef CompressedImageView<2> CompressedImageView2D;
/** @brief Three-dimensional compressed image view */
typedef CompressedImageView<3> CompressedImageView3D;
template<UnsignedInt dimensions> constexpr CompressedImageView<dimensions>::CompressedImageView(
#ifndef MAGNUM_TARGET_GLES
const CompressedPixelStorage storage,
#endif
const CompressedPixelFormat format, const VectorTypeFor<dimensions, Int>& size, const Containers::ArrayView<const void> data) noexcept:
#ifndef MAGNUM_TARGET_GLES
_storage{storage},
#endif
_format{format}, _size{size}, _data{reinterpret_cast<const char*>(data.data()), data.size()} {}
template<UnsignedInt dimensions> constexpr CompressedImageView<dimensions>::CompressedImageView(
#ifndef MAGNUM_TARGET_GLES
const CompressedPixelStorage storage,
#endif
const CompressedPixelFormat format, const VectorTypeFor<dimensions, Int>& size) noexcept:
#ifndef MAGNUM_TARGET_GLES
_storage{storage},
#endif
_format{format}, _size{size} {}
#ifndef MAGNUM_TARGET_GLES
template<UnsignedInt dimensions> constexpr CompressedImageView<dimensions>::CompressedImageView(const CompressedPixelFormat format, const VectorTypeFor<dimensions, Int>& size, const Containers::ArrayView<const void> data) noexcept: CompressedImageView{{}, format, size, data} {}
template<UnsignedInt dimensions> constexpr CompressedImageView<dimensions>::CompressedImageView(const CompressedPixelFormat format, const VectorTypeFor<dimensions, Int>& size) noexcept: CompressedImageView{{}, format, size} {}
#endif
}
#endif

5
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;

263
src/Magnum/PixelStorage.h

@ -26,13 +26,14 @@
*/
/** @file
* @brief
* @brief Class @ref Magnum::PixelStorage, @ref Magnum::CompressedPixelStorage
*/
#include <cstddef>
#include "Magnum/Magnum.h"
#include "Magnum/visibility.h"
#include "Magnum/Math/Vector3.h"
namespace Magnum {
@ -42,6 +43,266 @@ namespace Implementation {
template<UnsignedInt dimensions> std::size_t imageDataSize(PixelFormat format, PixelType type, Math::Vector<dimensions, Int> 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

46
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);

56
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<char>{data, 8}};
CompressedImage2D a{
#ifndef MAGNUM_TARGET_GLES
CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}),
#endif
CompressedPixelFormat::RGBAS3tcDxt1, {4, 4}, Containers::Array<char>{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<char>{data2, 16}};
CompressedImage2D c{
#ifndef MAGNUM_TARGET_GLES
CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}),
#endif
CompressedPixelFormat::RGBAS3tcDxt3, {8, 4}, Containers::Array<char>{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<char>{data, 8}};
auto data2 = new char[16];
a.setData(CompressedPixelFormat::RGBAS3tcDxt3, {8, 4}, Containers::Array<char>{data2, 16});
a.setData(
#ifndef MAGNUM_TARGET_GLES
CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}),
#endif
CompressedPixelFormat::RGBAS3tcDxt3, {8, 4}, Containers::Array<char>{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<char>{data, 8}};
const CompressedImage2D a{
#ifndef MAGNUM_TARGET_GLES
CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}),
#endif
CompressedPixelFormat::RGBAS3tcDxt1, {4, 4}, Containers::Array<char>{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);

28
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);

28
src/Magnum/Trade/ImageData.cpp

@ -27,6 +27,11 @@
namespace Magnum { namespace Trade {
template<UnsignedInt dimensions> PixelStorage ImageData<dimensions>::storage() const {
CORRADE_ASSERT(!_compressed, "Trade::ImageData::storage(): the image is compressed", {});
return _storage;
}
template<UnsignedInt dimensions> PixelFormat ImageData<dimensions>::format() const {
CORRADE_ASSERT(!_compressed, "Trade::ImageData::format(): the image is compressed", {});
return _format;
@ -37,8 +42,15 @@ template<UnsignedInt dimensions> PixelType ImageData<dimensions>::type() const {
return _type;
}
#ifndef MAGNUM_TARGET_GLES
template<UnsignedInt dimensions> CompressedPixelStorage ImageData<dimensions>::compressedStorage() const {
CORRADE_ASSERT(_compressed, "Trade::ImageData::compressedStorage(): the image is not compressed", {});
return _compressedStorage;
}
#endif
template<UnsignedInt dimensions> CompressedPixelFormat ImageData<dimensions>::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<dimensions>{_format, _type, _size}));
return ImageView<dimensions>{_format, _type, _size, _data};
CORRADE_ASSERT(!_compressed, "Trade::ImageData::type(): the image is compressed", (ImageView<dimensions>{_storage, _format, _type, _size}));
return ImageView<dimensions>{_storage, _format, _type, _size, _data};
}
template<UnsignedInt dimensions> ImageData<dimensions>::operator CompressedImageView<dimensions>()
@ -70,8 +82,16 @@ const &
const
#endif
{
#ifndef MAGNUM_TARGET_GLES
CORRADE_ASSERT(_compressed, "Trade::ImageData::type(): the image is not compressed", (CompressedImageView<dimensions>{_compressedStorage, _compressedFormat, _size}));
#else
CORRADE_ASSERT(_compressed, "Trade::ImageData::type(): the image is not compressed", (CompressedImageView<dimensions>{_compressedFormat, _size}));
return CompressedImageView<dimensions>{_compressedFormat, _size, _data};
#endif
return CompressedImageView<dimensions>{
#ifndef MAGNUM_TARGET_GLES
_compressedStorage,
#endif
_compressedFormat, _size, _data};
}
#ifndef DOXYGEN_GENERATING_OUTPUT

100
src/Magnum/Trade/ImageData.h

@ -58,6 +58,7 @@ template<UnsignedInt dimensions> 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<UnsignedInt dimensions> 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<dimensions, Int>& size, void* data): _compressed{false}, _format{format}, _type{type}, _size{size}, _data{reinterpret_cast<char*>(data), dataSize(size)} {}
explicit ImageData(PixelStorage storage, PixelFormat format, PixelType type, const VectorTypeFor<dimensions, Int>& size, void* data): _compressed{false}, _storage{storage}, _format{format}, _type{type}, _size{size}, _data{reinterpret_cast<char*>(data), dataSize(size)} {}
/** @overload
* Similar to the above, but uses default @ref PixelStorage parameters.
*/
explicit ImageData(PixelFormat format, PixelType type, const VectorTypeFor<dimensions, Int>& 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<dimensions, Int>& size, Containers::Array<char>&& data): _compressed{true}, _compressedFormat{format}, _size{size}, _data{std::move(data)} {}
explicit ImageData(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor<dimensions, Int>& size, Containers::Array<char>&& 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<dimensions, Int>& size, Containers::Array<char>&& data);
/** @brief Copying is not allowed */
ImageData(const ImageData<dimensions>&) = delete;
@ -130,11 +153,19 @@ template<UnsignedInt dimensions> class ImageData {
/*implicit*/ operator CompressedImageView<dimensions>() 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<UnsignedInt dimensions> 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<UnsignedInt dimensions> 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<UnsignedInt dimensions> ImageData<dimensions>::ImageData(
#ifndef MAGNUM_TARGET_GLES
const CompressedPixelStorage storage,
#endif
const CompressedPixelFormat format, const VectorTypeFor<dimensions, Int>& size, Containers::Array<char>&& data): _compressed{true},
#ifndef MAGNUM_TARGET_GLES
_compressedStorage{storage},
#endif
_compressedFormat{format}, _size{size}, _data{std::move(data)} {}
#ifndef MAGNUM_TARGET_GLES
template<UnsignedInt dimensions> inline ImageData<dimensions>::ImageData(const CompressedPixelFormat format, const VectorTypeFor<dimensions, Int>& size, Containers::Array<char>&& data): ImageData{{}, format, size, std::move(data)} {}
#endif
template<UnsignedInt dimensions> inline ImageData<dimensions>::ImageData(ImageData<dimensions>&& 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<UnsignedInt dimensions> inline ImageData<dimensions>::ImageData(ImageDa
template<UnsignedInt dimensions> inline ImageData<dimensions>& ImageData<dimensions>::operator=(ImageData<dimensions>&& 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);

30
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<char>{data, 8}};
Trade::ImageData2D a{
#ifndef MAGNUM_TARGET_GLES
CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}),
#endif
CompressedPixelFormat::RGBAS3tcDxt1, {4, 4}, Containers::Array<char>{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<char>{data, 8}};
Trade::ImageData2D a{
#ifndef MAGNUM_TARGET_GLES
CompressedPixelStorage{}.setCompressedBlockSize(Vector3i{4}),
#endif
CompressedPixelFormat::RGBAS3tcDxt1, {4, 4}, Containers::Array<char>{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);

Loading…
Cancel
Save