Browse Source

Compressed image support, part 6: Compressed* image classes.

Added (now empty) AbstractCompressedImage class that inherits (now also
empty) AbstractImage class.

Added CompressedBufferImage, CompressedImage and CompressedImageView
classes, which are just copies of BufferImage, Image and ImageView
classes with format/type pair replaced by just format, but they
additionally need data size parameter.

Because of different use cases in Trade, the Trade::ImageData class now
handles both uncompressed and compressed format, checking the API
usage with runtime assertions. The reason for this is that a material
could just reference a image file by ID and we need to be able to
extract image of that ID without prior knowledge whether it is
compressed or not. Requiring prior knowledge of image format from the
user would make both the API and the usage far more complicated than
having Trade::ImageData which handles both cases.

On the other hand, the Image*/CompressedImage* distinction is done for
easier usage and type-safe APIs in all other cases.
pull/107/head
Vladimír Vondruš 11 years ago
parent
commit
913a08e267
  1. 17
      src/Magnum/AbstractImage.h
  2. 17
      src/Magnum/BufferImage.cpp
  3. 114
      src/Magnum/BufferImage.h
  4. 1
      src/Magnum/CMakeLists.txt
  5. 10
      src/Magnum/Image.cpp
  6. 156
      src/Magnum/Image.h
  7. 82
      src/Magnum/ImageView.h
  8. 17
      src/Magnum/Magnum.h
  9. 97
      src/Magnum/Test/BufferImageGLTest.cpp
  10. 98
      src/Magnum/Test/ImageTest.cpp
  11. 28
      src/Magnum/Test/ImageViewTest.cpp
  12. 83
      src/Magnum/Trade/ImageData.cpp
  13. 157
      src/Magnum/Trade/ImageData.h
  14. 85
      src/Magnum/Trade/Test/ImageDataTest.cpp

17
src/Magnum/AbstractImage.h

@ -26,7 +26,7 @@
*/
/** @file
* @brief Class @ref Magnum::AbstractImage
* @brief Class @ref Magnum::AbstractImage, @ref Magnum::AbstractCompressedImage
*/
#include <cstddef>
@ -43,10 +43,11 @@ namespace Implementation {
}
/**
@brief Non-templated base for one-, two- or three-dimensional images
@brief Non-templated base for one-, two- or three-dimensional uncompressed images
See @ref Image, @ref ImageView, @ref BufferImage and @ref Trade::ImageData
documentation for more information.
@see @ref AbstractCompressedImage
@todo Where to put glClampColor() and glPixelStore() encapsulation? It is
needed in AbstractFramebuffer::read(), Texture::setImage() etc (i.e. all
functions operating with images). It also possibly needs to be "stackable"
@ -66,6 +67,18 @@ class AbstractImage {
Int _dummy;
};
/**
@brief Non-templated base for one-, two- or three-dimensional compressed images
See @ref CompressedImage, @ref CompressedImageView, @ref CompressedBufferImage
and @ref Trade::ImageData documentation for more information.
@see @ref AbstractImage
*/
class AbstractCompressedImage: public AbstractImage {
protected:
~AbstractCompressedImage() = default;
};
}
#endif

17
src/Magnum/BufferImage.cpp

@ -41,10 +41,27 @@ template<UnsignedInt dimensions> void BufferImage<dimensions>::setData(ColorForm
_buffer.setData({data, dataSize(size)}, usage);
}
template<UnsignedInt dimensions> CompressedBufferImage<dimensions>::CompressedBufferImage(CompressedColorFormat format, const VectorTypeFor<dimensions, Int>& size, Containers::ArrayView<const void> data, BufferUsage usage): _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> void CompressedBufferImage<dimensions>::setData(CompressedColorFormat format, const VectorTypeFor<dimensions, Int>& size, Containers::ArrayView<const void> data, BufferUsage usage) {
_format = format;
_size = size;
_buffer.setData(data, usage);
_dataSize = data.size();
}
#ifndef DOXYGEN_GENERATING_OUTPUT
template class MAGNUM_EXPORT BufferImage<1>;
template class MAGNUM_EXPORT BufferImage<2>;
template class MAGNUM_EXPORT BufferImage<3>;
template class MAGNUM_EXPORT CompressedBufferImage<1>;
template class MAGNUM_EXPORT CompressedBufferImage<2>;
template class MAGNUM_EXPORT CompressedBufferImage<3>;
#endif
#endif

114
src/Magnum/BufferImage.h

@ -27,7 +27,7 @@
#ifndef MAGNUM_TARGET_GLES2
/** @file
* @brief Class @ref Magnum::BufferImage, typedef @ref Magnum::BufferImage1D, @ref Magnum::BufferImage2D, @ref Magnum::BufferImage3D
* @brief Class @ref Magnum::BufferImage, @ref Magnum::CompressedBufferImage, typedef @ref Magnum::BufferImage1D, @ref Magnum::BufferImage2D, @ref Magnum::BufferImage3D, @ref Magnum::CompressedBufferImage1D, @ref Magnum::CompressedBufferImage2D, @ref Magnum::CompressedBufferImage3D
*/
#endif
@ -44,7 +44,8 @@ namespace Magnum {
Stores image data in GPU memory. Interchangeable with @ref Image,
@ref ImageView or @ref Trade::ImageData.
@see @ref BufferImage1D, @ref BufferImage2D, @ref BufferImage3D, @ref Buffer
@see @ref BufferImage1D, @ref BufferImage2D, @ref BufferImage3D,
@ref CompressedBufferImage, @ref Buffer
@requires_gles30 Pixel buffer objects are not available in OpenGL ES 2.0.
@requires_webgl20 Pixel buffer objects are not available in WebGL 1.0.
*/
@ -142,10 +143,109 @@ typedef BufferImage<2> BufferImage2D;
/** @brief Three-dimensional buffer image */
typedef BufferImage<3> BufferImage3D;
/**
@brief Compressed buffer image
Stores image data in GPU memory.
See @ref BufferImage for more information. Interchangeable with @ref CompressedImage,
@ref CompressedImageView or @ref Trade::ImageData.
@see @ref CompressedBufferImage1D, @ref CompressedBufferImage2D,
@ref CompressedBufferImage3D
@requires_gles30 Pixel buffer objects are not available in OpenGL ES 2.0.
@requires_webgl20 Pixel buffer objects are not available in WebGL 1.0.
*/
template<UnsignedInt dimensions> class CompressedBufferImage: public AbstractCompressedImage {
public:
enum: UnsignedInt {
Dimensions = dimensions /**< Image dimension count */
};
/**
* @brief Constructor
* @param format Format of compressed data
* @param size Image size
* @param data Image data
* @param usage Image buffer usage
*
* The data are *not* deleted after filling the buffer.
* @todo Make it more flexible (usable with
* @extension{ARB,buffer_storage}, avoiding relocations...)
*/
explicit CompressedBufferImage(CompressedColorFormat format, const VectorTypeFor<dimensions, Int>& size, Containers::ArrayView<const void> data, BufferUsage usage);
/**
* @brief Constructor
*
* Format is undefined, size is zero and buffer is empty, call
* @ref setData() to fill the image with data.
*/
/*implicit*/ CompressedBufferImage();
/** @brief Copying is not allowed */
CompressedBufferImage(const CompressedBufferImage<dimensions>&) = delete;
/** @brief Move constructor */
CompressedBufferImage(CompressedBufferImage<dimensions>&& other) noexcept;
/** @brief Copying is not allowed */
CompressedBufferImage<dimensions>& operator=(const CompressedBufferImage<dimensions>&) = delete;
/** @brief Move assignment */
CompressedBufferImage<dimensions>& operator=(CompressedBufferImage<dimensions>&& other) noexcept;
/** @brief Format of compressed data */
CompressedColorFormat format() const { return _format; }
/** @brief Image size */
VectorTypeFor<Dimensions, Int> size() const { return _size; }
/** @brief Image buffer */
Buffer& buffer() { return _buffer; }
/** @brief Raw data size */
std::size_t dataSize() const { return _dataSize; }
/**
* @brief Set image data
* @param format Format of compressed data
* @param size Image size
* @param data Image data
* @param usage Image buffer usage
*
* Updates the image buffer with given data. The data are *not* deleted
* after filling the buffer.
* @see @ref Buffer::setData()
* @todo Make it more flexible (usable with
* @extension{ARB,buffer_storage}, avoiding relocations...)
*/
void setData(CompressedColorFormat format, const VectorTypeFor<dimensions, Int>& size, Containers::ArrayView<const void> data, BufferUsage usage);
private:
CompressedColorFormat _format;
Math::Vector<Dimensions, Int> _size;
Buffer _buffer;
std::size_t _dataSize;
};
/** @brief One-dimensional compressed buffer image */
typedef CompressedBufferImage<1> CompressedBufferImage1D;
/** @brief Two-dimensional compressed buffer image */
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: AbstractImage{std::move(other)}, _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: AbstractCompressedImage{std::move(other)}, _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 {
AbstractImage::operator=(std::move(other));
using std::swap;
@ -155,6 +255,16 @@ template<UnsignedInt dimensions> inline BufferImage<dimensions>& BufferImage<dim
swap(_buffer, other._buffer);
return *this;
}
template<UnsignedInt dimensions> inline CompressedBufferImage<dimensions>& CompressedBufferImage<dimensions>::operator=(CompressedBufferImage<dimensions>&& other) noexcept {
AbstractCompressedImage::operator=(std::move(other));
using std::swap;
swap(_format, other._format);
swap(_size, other._size);
swap(_buffer, other._buffer);
swap(_dataSize, other._dataSize);
return *this;
}
#else
#error this header is not available in OpenGL ES 2.0 build
#endif

1
src/Magnum/CMakeLists.txt

@ -66,6 +66,7 @@ set(Magnum_SRCS
Trade/AbstractImageConverter.cpp
Trade/AbstractImporter.cpp
Trade/AbstractMaterialData.cpp
Trade/ImageData.cpp
Trade/MeshData2D.cpp
Trade/MeshData3D.cpp
Trade/MeshObjectData2D.cpp

10
src/Magnum/Image.cpp

@ -35,10 +35,20 @@ template<UnsignedInt dimensions> void Image<dimensions>::setData(ColorFormat for
_data = reinterpret_cast<char*>(data);
}
template<UnsignedInt dimensions> void CompressedImage<dimensions>::setData(CompressedColorFormat format, const VectorTypeFor<dimensions, Int>& size, Containers::Array<char>&& data) {
_format = format;
_size = size;
_data = std::move(data);
}
#ifndef DOXYGEN_GENERATING_OUTPUT
template class MAGNUM_EXPORT Image<1>;
template class MAGNUM_EXPORT Image<2>;
template class MAGNUM_EXPORT Image<3>;
template class MAGNUM_EXPORT CompressedImage<1>;
template class MAGNUM_EXPORT CompressedImage<2>;
template class MAGNUM_EXPORT CompressedImage<3>;
#endif
}

156
src/Magnum/Image.h

@ -26,9 +26,11 @@
*/
/** @file
* @brief Class @ref Magnum::Image, typedef @ref Magnum::Image1D, @ref Magnum::Image2D, @ref Magnum::Image3D
* @brief Class @ref Magnum::Image, @ref Magnum::CompressedImage typedef @ref Magnum::Image1D, @ref Magnum::Image2D, @ref Magnum::Image3D, @ref Magnum::CompressedImage1D, @ref Magnum::CompressedImage2D, @ref Magnum::CompressedImage3D
*/
#include <Corrade/Containers/Array.h>
#include "Magnum/ImageView.h"
namespace Magnum {
@ -38,7 +40,7 @@ namespace Magnum {
Stores image data on client memory. Interchangeable with @ref ImageView,
@ref BufferImage or @ref Trade::ImageData.
@see @ref Image1D, @ref Image2D, @ref Image3D
@see @ref Image1D, @ref Image2D, @ref Image3D, @ref CompressedImage
*/
template<UnsignedInt dimensions> class Image: public AbstractImage {
public:
@ -171,11 +173,134 @@ typedef Image<2> Image2D;
/** @brief Three-dimensional image */
typedef Image<3> Image3D;
/**
@brief Compressed image
Stores image data in client memory.
See @ref Image for more information. Interchangeable with
@ref CompressedImageView, @ref CompressedBufferImage or @ref Trade::ImageData.
@see @ref CompressedImage1D, @ref CompressedImage2D, @ref CompressedImage3D
*/
template<UnsignedInt dimensions> class CompressedImage: public AbstractCompressedImage {
public:
enum: UnsignedInt {
Dimensions = dimensions /**< Image dimension count */
};
/**
* @brief Constructor
* @param format Format of compressed data
* @param size Image size
* @param data Image data
*/
explicit CompressedImage(CompressedColorFormat format, const VectorTypeFor<dimensions, Int>& size, Containers::Array<char>&& data): _format{format}, _size{size}, _data{std::move(data)} {}
/**
* @brief Constructor
*
* Format is undefined, size is zero and data are empty, call
* @ref setData() to fill the image with data.
*/
/*implicit*/ CompressedImage(): _format{} {}
/** @brief Copying is not allowed */
CompressedImage(const CompressedImage<dimensions>&) = delete;
/** @brief Move constructor */
CompressedImage(CompressedImage<dimensions>&& other) noexcept;
/** @brief Copying is not allowed */
CompressedImage<dimensions>& operator=(const CompressedImage<dimensions>&) = delete;
/** @brief Move assignment */
CompressedImage<dimensions>& operator=(CompressedImage<dimensions>&& other) noexcept;
/** @brief Conversion to view */
/*implicit*/ operator CompressedImageView<dimensions>()
#ifndef CORRADE_GCC47_COMPATIBILITY
const &;
#else
const;
#endif
#ifndef CORRADE_GCC47_COMPATIBILITY
/** @overload */
/*implicit*/ operator CompressedImageView<dimensions>() const && = delete;
#endif
/** @brief Format of compressed data */
CompressedColorFormat format() const { return _format; }
/** @brief Image size */
VectorTypeFor<dimensions, Int> size() const { return _size; }
/** @brief Raw data */
Containers::ArrayView<char> data() { return _data; }
/** @overload */
Containers::ArrayView<const char> data() const { return _data; }
/**
* @brief Pointer to raw data
*
* @see @ref release()
*/
template<class T> T* data() {
return reinterpret_cast<T*>(_data.data());
}
/** @overload */
template<class T> const T* data() const {
return reinterpret_cast<const T*>(_data.data());
}
/**
* @brief Set image data
* @param format Format of compressed 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()
*/
void setData(CompressedColorFormat format, const VectorTypeFor<dimensions, Int>& size, Containers::Array<char>&& data);
/**
* @brief Release data storage
*
* Releases the ownership of the data pointer and resets internal state
* to default.
* @see @ref setData()
*/
Containers::Array<char> release();
private:
CompressedColorFormat _format;
Math::Vector<Dimensions, Int> _size;
Containers::Array<char> _data;
};
/** @brief One-dimensional compressed image */
typedef CompressedImage<1> CompressedImage1D;
/** @brief Two-dimensional compressed image */
typedef CompressedImage<2> CompressedImage2D;
/** @brief Three-dimensional compressed image */
typedef CompressedImage<3> CompressedImage3D;
template<UnsignedInt dimensions> inline Image<dimensions>::Image(Image<dimensions>&& other) noexcept: AbstractImage{std::move(other)}, _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: AbstractCompressedImage{std::move(other)}, _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 {
AbstractImage::operator=(std::move(other));
using std::swap;
@ -186,6 +311,15 @@ template<UnsignedInt dimensions> inline Image<dimensions>& Image<dimensions>::op
return *this;
}
template<UnsignedInt dimensions> inline CompressedImage<dimensions>& CompressedImage<dimensions>::operator=(CompressedImage<dimensions>&& other) noexcept {
AbstractCompressedImage::operator=(std::move(other));
using std::swap;
swap(_format, other._format);
swap(_size, other._size);
swap(_data, other._data);
return *this;
}
template<UnsignedInt dimensions> inline Image<dimensions>::operator ImageView<dimensions>()
#ifndef CORRADE_GCC47_COMPATIBILITY
const &
@ -196,6 +330,16 @@ const
return ImageView<dimensions>{_format, _type, _size, _data};
}
template<UnsignedInt dimensions> inline CompressedImage<dimensions>::operator CompressedImageView<dimensions>()
#ifndef CORRADE_GCC47_COMPATIBILITY
const &
#else
const
#endif
{
return CompressedImageView<dimensions>{_format, _size, _data};
}
template<UnsignedInt dimensions> inline char* Image<dimensions>::release() {
/** @todo I need `std::exchange` NOW. */
char* const data = _data;
@ -204,6 +348,14 @@ template<UnsignedInt dimensions> inline char* Image<dimensions>::release() {
return data;
}
template<UnsignedInt dimensions> inline Containers::Array<char> CompressedImage<dimensions>::release() {
/** @todo I need `std::exchange` NOW. */
Containers::Array<char> data{std::move(_data)};
_size = {};
_data = nullptr;
return data;
}
}
#endif

82
src/Magnum/ImageView.h

@ -26,9 +26,11 @@
*/
/** @file
* @brief Class @ref Magnum::ImageView, typedef @ref Magnum::ImageView1D, @ref Magnum::ImageView2D, @ref Magnum::ImageView3D
* @brief Class @ref Magnum::ImageView, @ref Magnum::CompressedImageView, typedef @ref Magnum::ImageView1D, @ref Magnum::ImageView2D, @ref Magnum::ImageView3D, @ref Magnum::CompressedImageView1D, @ref Magnum::CompressedImageView2D, @ref Magnum::CompressedImageView3D
*/
#include <Corrade/Containers/ArrayView.h>
#include "Magnum/Math/Vector3.h"
#include "Magnum/AbstractImage.h"
#include "Magnum/DimensionTraits.h"
@ -48,7 +50,8 @@ same properties for each frame, such as video stream. Thus it is not possible
to change image properties, only data pointer.
Interchangeable with @ref Image, @ref BufferImage or @ref Trade::ImageData.
@see @ref ImageView1D, @ref ImageView2D, @ref ImageView3D
@see @ref ImageView1D, @ref ImageView2D, @ref ImageView3D,
@ref CompressedImageView
*/
template<UnsignedInt dimensions> class ImageView: public AbstractImage {
public:
@ -129,6 +132,81 @@ typedef ImageView<2> ImageView2D;
/** @brief Three-dimensional image view */
typedef ImageView<3> ImageView3D;
/**
@brief Compressed image view
Adds information about dimensions and compression type to some data in memory.
See @ref ImageView for more information. Interchangeable with
@ref CompressedImage, @ref CompressedBufferImage or @ref Trade::ImageData.
@see @ref CompressedImageView1D, @ref CompressedImageView2D,
@ref CompressedImageView3D
*/
template<UnsignedInt dimensions> class CompressedImageView: public AbstractCompressedImage {
public:
enum: UnsignedInt {
Dimensions = dimensions /**< Image dimension count */
};
/**
* @brief Constructor
* @param format Format of compressed data
* @param size Image size
* @param data Image data
*/
constexpr explicit CompressedImageView(CompressedColorFormat format, const VectorTypeFor<dimensions, Int>& size, Containers::ArrayView<const void> data): _format{format}, _size{size}, _data{reinterpret_cast<const char*>(data.data()), data.size()} {}
/**
* @brief Constructor
* @param format Format of compressed data
* @param size Image size
*
* Data pointer is set to `nullptr`, call @ref setData() to fill the
* image with data.
*/
constexpr explicit CompressedImageView(CompressedColorFormat format, const VectorTypeFor<dimensions, Int>& size): _format{format}, _size{size} {}
/** @brief Format of compressed data */
CompressedColorFormat format() const { return _format; }
/** @brief Image size */
constexpr VectorTypeFor<dimensions, Int> size() const { return _size; }
/** @brief Raw data */
constexpr Containers::ArrayView<const char> data() const { return _data; }
/** @overload */
template<class T> const T* data() const {
return reinterpret_cast<const T*>(_data.data());
}
/**
* @brief Set image data
* @param data Image data
*
* Dimensions, color compnents and data type remains the same as
* passed in constructor. The data are not copied nor deleted on
* destruction.
*/
void setData(Containers::ArrayView<const void> data) {
_data = {reinterpret_cast<const char*>(data.data()), data.size()};
}
private:
CompressedColorFormat _format;
Math::Vector<Dimensions, Int> _size;
Containers::ArrayView<const char> _data;
};
/** @brief One-dimensional compressed image view */
typedef CompressedImageView<1> CompressedImageView1D;
/** @brief Two-dimensional compressed image view */
typedef CompressedImageView<2> CompressedImageView2D;
/** @brief Three-dimensional compressed image view */
typedef CompressedImageView<3> CompressedImageView3D;
}
#endif

17
src/Magnum/Magnum.h

@ -443,6 +443,11 @@ template<UnsignedInt> class BufferImage;
typedef BufferImage<1> BufferImage1D;
typedef BufferImage<2> BufferImage2D;
typedef BufferImage<3> BufferImage3D;
template<UnsignedInt> class CompressedBufferImage;
typedef CompressedBufferImage<1> CompressedBufferImage1D;
typedef CompressedBufferImage<2> CompressedBufferImage2D;
typedef CompressedBufferImage<3> CompressedBufferImage3D;
#endif
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
@ -480,18 +485,28 @@ typedef Image<1> Image1D;
typedef Image<2> Image2D;
typedef Image<3> Image3D;
template<UnsignedInt> class CompressedImage;
typedef CompressedImage<1> CompressedImage1D;
typedef CompressedImage<2> CompressedImage2D;
typedef CompressedImage<3> CompressedImage3D;
template<UnsignedInt> class ImageView;
typedef ImageView<1> ImageView1D;
typedef ImageView<2> ImageView2D;
typedef ImageView<3> ImageView3D;
#ifdef MAGNUM_BUILD_DEPRECATED
template<UnsignedInt dimensions> using CORRADE_DEPRECATED("use ImageView instead") ImageReference = ImageView<dimensions>;
template<UnsignedInt dimensions> using ImageReference CORRADE_DEPRECATED("use ImageView instead") = ImageView<dimensions>;
typedef CORRADE_DEPRECATED("use ImageView1D instead") ImageView1D ImageReference1D;
typedef CORRADE_DEPRECATED("use ImageView2D instead") ImageView2D ImageReference2D;
typedef CORRADE_DEPRECATED("use ImageView3D instead") ImageView3D ImageReference3D;
#endif
template<UnsignedInt> class CompressedImageView;
typedef CompressedImageView<1> CompressedImageView1D;
typedef CompressedImageView<2> CompressedImageView2D;
typedef CompressedImageView<3> CompressedImageView3D;
enum class MeshPrimitive: GLenum;
class Mesh;

97
src/Magnum/Test/BufferImageGLTest.cpp

@ -35,18 +35,26 @@ struct BufferImageGLTest: AbstractOpenGLTester {
explicit BufferImageGLTest();
void construct();
void constructCompressed();
void constructCopy();
void constructCopyCompressed();
void constructMove();
void constructMoveCompressed();
void setData();
void setDataCompressed();
};
BufferImageGLTest::BufferImageGLTest() {
addTests({&BufferImageGLTest::construct,
&BufferImageGLTest::constructCompressed,
&BufferImageGLTest::constructCopy,
&BufferImageGLTest::constructCopyCompressed,
&BufferImageGLTest::constructMove,
&BufferImageGLTest::constructMoveCompressed,
&BufferImageGLTest::setData});
&BufferImageGLTest::setData,
&BufferImageGLTest::setDataCompressed});
}
void BufferImageGLTest::construct() {
@ -70,11 +78,37 @@ void BufferImageGLTest::construct() {
#endif
}
void BufferImageGLTest::constructCompressed() {
const char data[] = { 'a', 0, 0, 0, 'b', 0, 0, 0 };
CompressedBufferImage2D a{CompressedColorFormat::RGBAS3tcDxt1, {4, 4}, data, BufferUsage::StaticDraw};
#ifndef MAGNUM_TARGET_GLES
const auto imageData = a.buffer().data();
#endif
MAGNUM_VERIFY_NO_ERROR();
CORRADE_COMPARE(a.format(), CompressedColorFormat::RGBAS3tcDxt1);
CORRADE_COMPARE(a.size(), Vector2i(4, 4));
CORRADE_COMPARE(a.dataSize(), 8);
/** @todo How to verify the contents in ES? */
#ifndef MAGNUM_TARGET_GLES
CORRADE_COMPARE_AS(imageData, Containers::ArrayView<const char>{data},
TestSuite::Compare::Container);
#endif
}
void BufferImageGLTest::constructCopy() {
CORRADE_VERIFY(!(std::is_constructible<BufferImage2D, const BufferImage2D&>{}));
CORRADE_VERIFY(!(std::is_assignable<BufferImage2D, const BufferImage2D&>{}));
}
void BufferImageGLTest::constructCopyCompressed() {
CORRADE_VERIFY(!(std::is_constructible<CompressedBufferImage2D, const CompressedBufferImage2D&>{}));
CORRADE_VERIFY(!(std::is_assignable<CompressedBufferImage2D, const CompressedBufferImage2D&>{}));
}
void BufferImageGLTest::constructMove() {
const char data[4] = { 'a', 'b', 'c', 'd' };
BufferImage2D a(ColorFormat::Red, ColorType::UnsignedByte, {4, 1}, data, BufferUsage::StaticDraw);
@ -110,6 +144,43 @@ void BufferImageGLTest::constructMove() {
CORRADE_COMPARE(c.buffer().id(), id);
}
void BufferImageGLTest::constructMoveCompressed() {
const char data[] = { 'a', 0, 0, 0, 'b', 0, 0, 0 };
CompressedBufferImage2D a{CompressedColorFormat::RGBAS3tcDxt1, {4, 4}, data, BufferUsage::StaticDraw};
const Int id = a.buffer().id();
MAGNUM_VERIFY_NO_ERROR();
CORRADE_VERIFY(id > 0);
CompressedBufferImage2D b{std::move(a)};
CORRADE_COMPARE(a.buffer().id(), 0);
CORRADE_COMPARE(a.size(), Vector2i());
CORRADE_COMPARE(a.dataSize(), 0);
CORRADE_COMPARE(b.format(), CompressedColorFormat::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{CompressedColorFormat::RGBAS3tcDxt1, {8, 4}, data2, BufferUsage::StaticDraw};
const Int cId = c.buffer().id();
c = std::move(b);
MAGNUM_VERIFY_NO_ERROR();
CORRADE_VERIFY(cId > 0);
CORRADE_COMPARE(b.buffer().id(), cId);
CORRADE_COMPARE(b.size(), Vector2i(8, 4));
CORRADE_COMPARE(b.dataSize(), 16);
CORRADE_COMPARE(c.format(), CompressedColorFormat::RGBAS3tcDxt1);
CORRADE_COMPARE(c.size(), Vector2i(4, 4));
CORRADE_COMPARE(c.dataSize(), 8);
CORRADE_COMPARE(c.buffer().id(), id);
}
void BufferImageGLTest::setData() {
const char data[4] = { 'a', 'b', 'c', 'd' };
BufferImage2D a(ColorFormat::Red, ColorType::UnsignedByte, {4, 1}, data, BufferUsage::StaticDraw);
@ -127,6 +198,30 @@ void BufferImageGLTest::setData() {
CORRADE_COMPARE(a.type(), ColorType::UnsignedShort);
CORRADE_COMPARE(a.size(), Vector2i(1, 2));
/** @todo How to verify the contents in ES? */
#ifndef MAGNUM_TARGET_GLES
CORRADE_COMPARE_AS(imageData, Containers::ArrayView<const UnsignedShort>{data2},
TestSuite::Compare::Container);
#endif
}
void BufferImageGLTest::setDataCompressed() {
const char data[] = { 'a', 0, 0, 0, 'b', 0, 0, 0 };
CompressedBufferImage2D a{CompressedColorFormat::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(CompressedColorFormat::RGBAS3tcDxt3, {8, 4}, data2, BufferUsage::StaticDraw);
#ifndef MAGNUM_TARGET_GLES
const auto imageData = a.buffer().data();
#endif
MAGNUM_VERIFY_NO_ERROR();
CORRADE_COMPARE(a.format(), CompressedColorFormat::RGBAS3tcDxt3);
CORRADE_COMPARE(a.size(), Vector2i(8, 4));
CORRADE_COMPARE(a.dataSize(), 16);
/** @todo How to verify the contents in ES? */
#ifndef MAGNUM_TARGET_GLES
CORRADE_COMPARE_AS(imageData, Containers::ArrayView<const char>{data2},

98
src/Magnum/Test/ImageTest.cpp

@ -34,22 +34,34 @@ struct ImageTest: TestSuite::Tester {
explicit ImageTest();
void construct();
void constructCompressed();
void constructCopy();
void constructCopyCompressed();
void constructMove();
void constructMoveCompressed();
void setData();
void setDataCompressed();
void toReference();
void toReferenceCommpressed();
void release();
void releaseCompressed();
};
ImageTest::ImageTest() {
addTests({&ImageTest::construct,
&ImageTest::constructCompressed,
&ImageTest::constructCopy,
&ImageTest::constructCopyCompressed,
&ImageTest::constructMove,
&ImageTest::constructMoveCompressed,
&ImageTest::setData,
&ImageTest::setDataCompressed,
&ImageTest::toReference,
&ImageTest::release});
&ImageTest::toReferenceCommpressed,
&ImageTest::release,
&ImageTest::releaseCompressed});
}
void ImageTest::construct() {
@ -62,11 +74,26 @@ void ImageTest::construct() {
CORRADE_COMPARE(a.data(), data);
}
void ImageTest::constructCompressed() {
auto data = new char[8];
CompressedImage2D a{CompressedColorFormat::RGBAS3tcDxt1, {4, 4}, Containers::Array<char>{data, 8}};
CORRADE_COMPARE(a.format(), CompressedColorFormat::RGBAS3tcDxt1);
CORRADE_COMPARE(a.size(), Vector2i(4, 4));
CORRADE_COMPARE(a.data(), data);
CORRADE_COMPARE(a.data().size(), 8);
}
void ImageTest::constructCopy() {
CORRADE_VERIFY(!(std::is_constructible<Image2D, const Image2D&>{}));
CORRADE_VERIFY(!(std::is_assignable<Image2D, const Image2D&>{}));
}
void ImageTest::constructCopyCompressed() {
CORRADE_VERIFY(!(std::is_constructible<CompressedImage2D, const CompressedImage2D&>{}));
CORRADE_VERIFY(!(std::is_assignable<CompressedImage2D, const CompressedImage2D&>{}));
}
void ImageTest::constructMove() {
auto data = new char[3];
Image2D a(ColorFormat::Red, ColorType::UnsignedByte, {1, 3}, data);
@ -93,6 +120,33 @@ void ImageTest::constructMove() {
CORRADE_COMPARE(c.data(), data);
}
void ImageTest::constructMoveCompressed() {
auto data = new char[8];
CompressedImage2D a{CompressedColorFormat::RGBAS3tcDxt1, {4, 4}, Containers::Array<char>{data, 8}};
CompressedImage2D b{std::move(a)};
CORRADE_COMPARE(a.data(), nullptr);
CORRADE_COMPARE(a.size(), Vector2i());
CORRADE_COMPARE(b.format(), CompressedColorFormat::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{CompressedColorFormat::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));
CORRADE_COMPARE(c.format(), CompressedColorFormat::RGBAS3tcDxt1);
CORRADE_COMPARE(c.size(), Vector2i(4, 4));
CORRADE_COMPARE(c.data(), data);
CORRADE_COMPARE(c.data().size(), 8);
}
void ImageTest::setData() {
auto data = new char[3];
Image2D a(ColorFormat::Red, ColorType::UnsignedByte, {1, 3}, data);
@ -105,6 +159,18 @@ void ImageTest::setData() {
CORRADE_COMPARE(a.data(), data2);
}
void ImageTest::setDataCompressed() {
auto data = new char[8];
CompressedImage2D a{CompressedColorFormat::RGBAS3tcDxt1, {4, 4}, Containers::Array<char>{data, 8}};
auto data2 = new char[16];
a.setData(CompressedColorFormat::RGBAS3tcDxt3, {8, 4}, Containers::Array<char>{data2, 16});
CORRADE_COMPARE(a.format(), CompressedColorFormat::RGBAS3tcDxt3);
CORRADE_COMPARE(a.size(), Vector2i(8, 4));
CORRADE_COMPARE(a.data(), data2);
CORRADE_COMPARE(a.data().size(), 16);
}
void ImageTest::toReference() {
auto data = new char[3];
const Image2D a(ColorFormat::Red, ColorType::UnsignedByte, {1, 3}, data);
@ -125,6 +191,26 @@ void ImageTest::toReference() {
}
}
void ImageTest::toReferenceCommpressed() {
auto data = new char[8];
const CompressedImage2D a{CompressedColorFormat::RGBAS3tcDxt1, {4, 4}, Containers::Array<char>{data, 8}};
CompressedImageView2D b = a;
CORRADE_COMPARE(b.format(), CompressedColorFormat::RGBAS3tcDxt1);
CORRADE_COMPARE(b.size(), Vector2i(4, 4));
CORRADE_COMPARE(b.data(), data);
CORRADE_COMPARE(b.data().size(), 8);
CORRADE_VERIFY((std::is_convertible<const CompressedImage2D&, CompressedImageView2D>::value));
{
#ifdef CORRADE_GCC47_COMPATIBILITY
CORRADE_EXPECT_FAIL("Rvalue references for *this are not supported in GCC < 4.8.1.");
#endif
CORRADE_VERIFY(!(std::is_convertible<const CompressedImage2D, CompressedImageView2D>::value));
CORRADE_VERIFY(!(std::is_convertible<const CompressedImage2D&&, CompressedImageView2D>::value));
}
}
void ImageTest::release() {
char data[] = {'c', 'a', 'f', 'e'};
Image2D a(ColorFormat::Red, ColorType::UnsignedByte, {1, 4}, data);
@ -135,6 +221,16 @@ void ImageTest::release() {
CORRADE_COMPARE(a.size(), Vector2i());
}
void ImageTest::releaseCompressed() {
char data[8];
CompressedImage2D a{CompressedColorFormat::RGBAS3tcDxt1, {4, 4}, Containers::Array<char>{data, 8}};
const char* const pointer = a.release().release();
CORRADE_COMPARE(pointer, data);
CORRADE_COMPARE(a.data(), nullptr);
CORRADE_COMPARE(a.size(), Vector2i());
}
}}
CORRADE_TEST_MAIN(Magnum::Test::ImageTest)

28
src/Magnum/Test/ImageViewTest.cpp

@ -34,12 +34,18 @@ struct ImageViewTest: TestSuite::Tester {
explicit ImageViewTest();
void construct();
void constructCompressed();
void setData();
void setDataCompressed();
};
ImageViewTest::ImageViewTest() {
addTests({&ImageViewTest::construct,
&ImageViewTest::setData});
&ImageViewTest::constructCompressed,
&ImageViewTest::setData,
&ImageViewTest::setDataCompressed});
}
void ImageViewTest::construct() {
@ -52,6 +58,15 @@ void ImageViewTest::construct() {
CORRADE_COMPARE(a.data(), data);
}
void ImageViewTest::constructCompressed() {
const char data[8]{};
CompressedImageView2D a{CompressedColorFormat::RGBAS3tcDxt1, {4, 4}, data};
CORRADE_COMPARE(a.format(), CompressedColorFormat::RGBAS3tcDxt1);
CORRADE_COMPARE(a.size(), Vector2i(4, 4));
CORRADE_COMPARE(a.data(), data);
}
void ImageViewTest::setData() {
const char data[3]{};
ImageView2D a(ColorFormat::Red, ColorType::UnsignedByte, {1, 3}, data);
@ -64,6 +79,17 @@ void ImageViewTest::setData() {
CORRADE_COMPARE(a.data(), data2);
}
void ImageViewTest::setDataCompressed() {
const char data[8]{};
CompressedImageView2D a{CompressedColorFormat::RGBAS3tcDxt1, {4, 4}, data};
const char data2[16]{};
a.setData(data2);
CORRADE_COMPARE(a.format(), CompressedColorFormat::RGBAS3tcDxt1);
CORRADE_COMPARE(a.size(), Vector2i(4, 4));
CORRADE_COMPARE(a.data(), data2);
}
}}
CORRADE_TEST_MAIN(Magnum::Test::ImageViewTest)

83
src/Magnum/Trade/ImageData.cpp

@ -0,0 +1,83 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015
Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include "ImageData.h"
namespace Magnum { namespace Trade {
template<UnsignedInt dimensions> ColorFormat ImageData<dimensions>::format() const {
CORRADE_ASSERT(!_compressed, "Trade::ImageData::format(): the image is compressed", {});
return _format;
}
template<UnsignedInt dimensions> ColorType ImageData<dimensions>::type() const {
CORRADE_ASSERT(!_compressed, "Trade::ImageData::type(): the image is compressed", {});
return _type;
}
template<UnsignedInt dimensions> CompressedColorFormat ImageData<dimensions>::compressedFormat() const {
CORRADE_ASSERT(_compressed, "Trade::ImageData::format(): the image is not compressed", {});
return _compressedFormat;
}
template<UnsignedInt dimensions> std::size_t ImageData<dimensions>::pixelSize() const {
CORRADE_ASSERT(!_compressed, "Trade::ImageData::pixelSize(): the image is compressed", {});
return Implementation::imagePixelSize(_format, _type);
}
template<UnsignedInt dimensions> std::size_t ImageData<dimensions>::dataSize(const VectorTypeFor< dimensions, Int >& size) const {
CORRADE_ASSERT(!_compressed, "Trade::ImageData::dataSize(): the image is compressed", {});
return Implementation::imageDataSize<dimensions>(*this, _format, _type, size);
}
template<UnsignedInt dimensions> ImageData<dimensions>::operator ImageView<dimensions>()
#ifndef CORRADE_GCC47_COMPATIBILITY
const &
#else
const
#endif
{
CORRADE_ASSERT(!_compressed, "Trade::ImageData::type(): the image is compressed", (ImageView<dimensions>{_format, _type, _size}));
return ImageView<dimensions>{_format, _type, _size, _data};
}
template<UnsignedInt dimensions> ImageData<dimensions>::operator CompressedImageView<dimensions>()
#ifndef CORRADE_GCC47_COMPATIBILITY
const &
#else
const
#endif
{
CORRADE_ASSERT(_compressed, "Trade::ImageData::type(): the image is not compressed", (CompressedImageView<dimensions>{_compressedFormat, _size}));
return CompressedImageView<dimensions>{_compressedFormat, _size, _data};
}
#ifndef DOXYGEN_GENERATING_OUTPUT
template class MAGNUM_EXPORT ImageData<1>;
template class MAGNUM_EXPORT ImageData<2>;
template class MAGNUM_EXPORT ImageData<3>;
#endif
}}

157
src/Magnum/Trade/ImageData.h

@ -29,6 +29,8 @@
* @brief Class @ref Magnum::Trade::ImageData, typedef @ref Magnum::Trade::ImageData1D, @ref Magnum::Trade::ImageData2D, @ref Magnum::Trade::ImageData3D
*/
#include <Corrade/Containers/Array.h>
#include "Magnum/ImageView.h"
namespace Magnum { namespace Trade {
@ -36,18 +38,26 @@ namespace Magnum { namespace Trade {
/**
@brief Image data
Access to image data provided by @ref AbstractImporter subclasses.
Interchangeable with @ref Image, @ref ImageView or @ref BufferImage.
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 ImageView. Compressed images have just the @ref compressedFormat()
property and are convertible to @ref CompressedImageView.
Uncompressed image is interchangeable with @ref Image, @ref ImageView or
@ref BufferImage, compressed with @ref CompressedImage, @ref CompressedImageView
or @ref CompressedBufferImage.
@see @ref ImageData1D, @ref ImageData2D, @ref ImageData3D
*/
template<UnsignedInt dimensions> class ImageData: public AbstractImage {
template<UnsignedInt dimensions> class ImageData: public AbstractCompressedImage {
public:
enum: UnsignedInt {
Dimensions = dimensions /**< Image dimension count */
};
/**
* @brief Constructor
* @brief Construct uncompressed image data
* @param format Format of pixel data
* @param type Data type of pixel data
* @param size Image size
@ -56,7 +66,18 @@ template<UnsignedInt dimensions> class ImageData: public AbstractImage {
* Note that the image data are not copied on construction, but they
* are deleted on class destruction.
*/
explicit ImageData(ColorFormat format, ColorType type, const VectorTypeFor<dimensions, Int>& size, void* data): _format{format}, _type{type}, _size{size}, _data{reinterpret_cast<char*>(data)} {}
explicit ImageData(ColorFormat format, ColorType type, const VectorTypeFor<dimensions, Int>& size, void* data): _compressed{false}, _format{format}, _type{type}, _size{size}, _data{reinterpret_cast<char*>(data), dataSize(size)} {}
/**
* @brief Construct compressed image data
* @param format Format of compressed 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.
*/
explicit ImageData(CompressedColorFormat format, const VectorTypeFor<dimensions, Int>& size, Containers::Array<char>&& data): _compressed{true}, _compressedFormat{format}, _size{size}, _data{std::move(data)} {}
/** @brief Copying is not allowed */
ImageData(const ImageData<dimensions>&) = delete;
@ -70,10 +91,15 @@ template<UnsignedInt dimensions> class ImageData: public AbstractImage {
/** @brief Move assignment */
ImageData<dimensions>& operator=(ImageData<dimensions>&& other) noexcept;
/** @brief Destructor */
~ImageData() { delete[] _data; }
/** @brief Whether the image is compressed */
bool isCompressed() const { return _compressed; }
/** @brief Conversion to view */
/**
* @brief Conversion to view
*
* The image is expected to be uncompressed.
* @see @ref isCompressed()
*/
/*implicit*/ operator ImageView<dimensions>()
#ifndef CORRADE_GCC47_COMPATIBILITY
const &;
@ -86,35 +112,86 @@ template<UnsignedInt dimensions> class ImageData: public AbstractImage {
/*implicit*/ operator ImageView<dimensions>() const && = delete;
#endif
/** @brief Format of pixel data */
ColorFormat format() const { return _format; }
/**
* @brief Conversion to compressed view
*
* The image is expected to be compressed.
* @see @ref isCompressed()
*/
/*implicit*/ operator CompressedImageView<dimensions>()
#ifndef CORRADE_GCC47_COMPATIBILITY
const &;
#else
const;
#endif
/** @brief Data type of pixel data */
ColorType type() const { return _type; }
#ifndef CORRADE_GCC47_COMPATIBILITY
/** @overload */
/*implicit*/ operator CompressedImageView<dimensions>() const && = delete;
#endif
/** @brief Pixel size (in bytes) */
std::size_t pixelSize() const { return Implementation::imagePixelSize(_format, _type); }
/**
* @brief Format of pixel data
*
* The image is expected to be uncompressed.
* @see @ref isCompressed()
*/
ColorFormat format() const;
/**
* @brief Data type of pixel data
*
* The image is expected to be uncompressed.
* @see @ref isCompressed()
*/
ColorType type() const;
/**
* @brief Format of compressed data
*
* The image is expected to be compressed.
* @see @ref isCompressed()
*/
CompressedColorFormat compressedFormat() const;
/**
* @brief Pixel size (in bytes)
*
* The image is expected to be uncompressed.
* @see @ref isCompressed()
*/
std::size_t pixelSize() const;
/** @brief Image size */
VectorTypeFor<dimensions, Int> size() const { return _size; }
/** @copydoc Image::dataSize() */
std::size_t dataSize(const VectorTypeFor<dimensions, Int>& size) const {
return Implementation::imageDataSize<dimensions>(*this, _format, _type, size);
}
/**
* @brief Size of data required to store uncompressed image of given size
*
* The image is expected to be uncompressed. Takes color format, type
* and row alignment of this image into account.
* @see @ref isCompressed(), @ref pixelSize()
*/
std::size_t dataSize(const VectorTypeFor<dimensions, Int>& size) const;
/** @brief Raw data */
Containers::ArrayView<char> data() { return _data; }
/** @overload */
Containers::ArrayView<const char> data() const { return _data; }
/**
* @brief Pointer to raw data
*
* @see @ref release()
*/
template<class T = char> T* data() {
return reinterpret_cast<T*>(_data);
template<class T> T* data() {
return reinterpret_cast<T*>(_data.data());
}
/** @overload */
template<class T = char> const T* data() const {
return reinterpret_cast<const T*>(_data);
template<class T> const T* data() const {
return reinterpret_cast<const T*>(_data.data());
}
/**
@ -124,13 +201,17 @@ template<UnsignedInt dimensions> class ImageData: public AbstractImage {
* to default. Deleting the returned array is then user responsibility.
* @see @ref data()
*/
char* release();
Containers::Array<char> release();
private:
ColorFormat _format;
bool _compressed;
union {
ColorFormat _format;
CompressedColorFormat _compressedFormat;
};
ColorType _type;
Math::Vector<Dimensions, Int> _size;
char* _data;
Containers::Array<char> _data;
};
/** @brief One-dimensional image */
@ -142,34 +223,28 @@ typedef ImageData<2> ImageData2D;
/** @brief Three-dimensional image */
typedef ImageData<3> ImageData3D;
template<UnsignedInt dimensions> inline ImageData<dimensions>::ImageData(ImageData<dimensions>&& other) noexcept: AbstractImage{std::move(other)}, _format{std::move(other._format)}, _type{std::move(other._type)}, _size{std::move(other._size)}, _data{std::move(other._data)} {
template<UnsignedInt dimensions> inline ImageData<dimensions>::ImageData(ImageData<dimensions>&& other) noexcept: AbstractCompressedImage{std::move(other)}, _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);
other._size = {};
other._data = nullptr;
}
template<UnsignedInt dimensions> inline ImageData<dimensions>& ImageData<dimensions>::operator=(ImageData<dimensions>&& other) noexcept {
AbstractImage::operator=(std::move(other));
AbstractCompressedImage::operator=(std::move(other));
using std::swap;
swap(_format, other._format);
swap(_compressed, other._compressed);
if(_compressed) swap(_compressedFormat, other._compressedFormat);
else swap(_format, other._format);
swap(_type, other._type);
swap(_size, other._size);
swap(_data, other._data);
return *this;
}
template<UnsignedInt dimensions> inline ImageData<dimensions>::operator ImageView<dimensions>()
#ifndef CORRADE_GCC47_COMPATIBILITY
const &
#else
const
#endif
{
return ImageView<dimensions>(_format, _type, _size, _data);
}
template<UnsignedInt dimensions> inline char* ImageData<dimensions>::release() {
/** @todo I need `std::exchange` NOW. */
char* const data = _data;
template<UnsignedInt dimensions> inline Containers::Array<char> ImageData<dimensions>::release() {
Containers::Array<char> data{std::move(_data)};
_size = {};
_data = nullptr;
return data;

85
src/Magnum/Trade/Test/ImageDataTest.cpp

@ -35,32 +35,52 @@ class ImageDataTest: public TestSuite::Tester {
explicit ImageDataTest();
void construct();
void constructCompressed();
void constructCopy();
void constructMove();
void constructMoveCompressed();
void toReference();
void toReferenceCompressed();
void release();
void releaseCompressed();
};
ImageDataTest::ImageDataTest() {
addTests({&ImageDataTest::construct,
&ImageDataTest::constructCompressed,
&ImageDataTest::constructCopy,
&ImageDataTest::constructMove,
&ImageDataTest::constructMoveCompressed,
&ImageDataTest::toReference,
&ImageDataTest::release});
&ImageDataTest::toReferenceCompressed,
&ImageDataTest::release,
&ImageDataTest::releaseCompressed});
}
void ImageDataTest::construct() {
auto data = new char[3];
Trade::ImageData2D a(ColorFormat::Red, ColorType::UnsignedByte, {1, 3}, data);
CORRADE_VERIFY(!a.isCompressed());
CORRADE_COMPARE(a.format(), ColorFormat::Red);
CORRADE_COMPARE(a.type(), ColorType::UnsignedByte);
CORRADE_COMPARE(a.size(), Vector2i(1, 3));
CORRADE_COMPARE(a.data(), data);
}
void ImageDataTest::constructCompressed() {
auto data = new char[8];
Trade::ImageData2D a{CompressedColorFormat::RGBAS3tcDxt1, {4, 4}, Containers::Array<char>{data, 8}};
CORRADE_VERIFY(a.isCompressed());
CORRADE_COMPARE(a.compressedFormat(), CompressedColorFormat::RGBAS3tcDxt1);
CORRADE_COMPARE(a.size(), Vector2i(4, 4));
CORRADE_COMPARE(a.data(), data);
CORRADE_COMPARE(a.data().size(), 8);
}
void ImageDataTest::constructCopy() {
CORRADE_VERIFY(!(std::is_constructible<Trade::ImageData2D, const Trade::ImageData2D&>{}));
CORRADE_VERIFY(!(std::is_assignable<Trade::ImageData2D, const Trade::ImageData2D&>{}));
@ -74,6 +94,7 @@ void ImageDataTest::constructMove() {
CORRADE_COMPARE(a.data(), nullptr);
CORRADE_COMPARE(a.size(), Vector2i());
CORRADE_VERIFY(!b.isCompressed());
CORRADE_COMPARE(b.format(), ColorFormat::Red);
CORRADE_COMPARE(b.type(), ColorType::UnsignedByte);
CORRADE_COMPARE(b.size(), Vector2i(1, 3));
@ -86,12 +107,42 @@ void ImageDataTest::constructMove() {
CORRADE_COMPARE(b.data(), data2);
CORRADE_COMPARE(b.size(), Vector2i(2, 6));
CORRADE_VERIFY(!c.isCompressed());
CORRADE_COMPARE(c.format(), ColorFormat::Red);
CORRADE_COMPARE(c.type(), ColorType::UnsignedByte);
CORRADE_COMPARE(c.size(), Vector2i(1, 3));
CORRADE_COMPARE(c.data(), data);
}
void ImageDataTest::constructMoveCompressed() {
auto data = new char[8];
Trade::ImageData2D a{CompressedColorFormat::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());
CORRADE_COMPARE(b.compressedFormat(), CompressedColorFormat::RGBAS3tcDxt1);
CORRADE_COMPARE(b.size(), Vector2i(4, 4));
CORRADE_COMPARE(b.data(), data);
CORRADE_COMPARE(b.data().size(), 8);
auto data2 = new char[16];
Trade::ImageData2D c{CompressedColorFormat::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));
CORRADE_VERIFY(c.isCompressed());
CORRADE_COMPARE(c.compressedFormat(), CompressedColorFormat::RGBAS3tcDxt1);
CORRADE_COMPARE(c.size(), Vector2i(4, 4));
CORRADE_COMPARE(c.data(), data);
CORRADE_COMPARE(c.data().size(), 8);
}
void ImageDataTest::toReference() {
auto data = new char[3];
const Trade::ImageData2D a(ColorFormat::Red, ColorType::UnsignedByte, {1, 3}, data);
@ -112,10 +163,40 @@ void ImageDataTest::toReference() {
}
}
void ImageDataTest::toReferenceCompressed() {
auto data = new char[8];
const Trade::ImageData2D a{CompressedColorFormat::RGBAS3tcDxt1, {4, 4}, Containers::Array<char>{data, 8}};
CompressedImageView2D b = a;
CORRADE_COMPARE(b.format(), CompressedColorFormat::RGBAS3tcDxt1);
CORRADE_COMPARE(b.size(), Vector2i(4, 4));
CORRADE_COMPARE(b.data(), data);
CORRADE_COMPARE(b.data().size(), 8);
CORRADE_VERIFY((std::is_convertible<const Trade::ImageData2D&, CompressedImageView2D>::value));
{
#ifdef CORRADE_GCC47_COMPATIBILITY
CORRADE_EXPECT_FAIL("Rvalue references for *this are not supported in GCC < 4.8.1.");
#endif
CORRADE_VERIFY(!(std::is_convertible<const Trade::ImageData2D, CompressedImageView2D>::value));
CORRADE_VERIFY(!(std::is_convertible<const Trade::ImageData2D&&, CompressedImageView2D>::value));
}
}
void ImageDataTest::release() {
char data[] = {'b', 'e', 'e', 'r'};
Trade::ImageData2D a(ColorFormat::Red, ColorType::UnsignedByte, {1, 4}, data);
const char* const pointer = a.release();
const char* const pointer = a.release().release();
CORRADE_COMPARE(pointer, data);
CORRADE_COMPARE(a.data(), nullptr);
CORRADE_COMPARE(a.size(), Vector2i());
}
void ImageDataTest::releaseCompressed() {
char data[8];
Trade::ImageData2D a{CompressedColorFormat::RGBAS3tcDxt1, {4, 4}, Containers::Array<char>{data, 8}};
const char* const pointer = a.release().release();
CORRADE_COMPARE(pointer, data);
CORRADE_COMPARE(a.data(), nullptr);

Loading…
Cancel
Save