diff --git a/src/AbstractTexture.h b/src/AbstractTexture.h index 0a149e642..d52d65595 100644 --- a/src/AbstractTexture.h +++ b/src/AbstractTexture.h @@ -271,6 +271,18 @@ class MAGNUM_EXPORT AbstractTexture { */ inline static void set(Target target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector& dimensions, ColorFormat colorFormat, Type type, const void* data); + /** + * @brief Set texture data from image + * @param target %Target + * @param mipLevel Mip level + * @param internalFormat Internal texture format + * @param image Image, BufferedImage or for example + * Trade::ImageData of the same dimension count + * + * Calls set() with image data. + */ + template inline static void set(Target target, GLint mipLevel, InternalFormat internalFormat, T* image); + /** * @brief Set texture subdata * @param target %Target @@ -285,6 +297,18 @@ class MAGNUM_EXPORT AbstractTexture { * depending on dimension count. */ inline static void setSub(SubTarget target, GLint mipLevel, const Math::Vector& offset, const Math::Vector& dimensions, ColorFormat colorFormat, Type type, const void* data); + + /** + * @brief Set texture subdata from image + * @param target %Target + * @param mipLevel Mip level + * @param offset Offset where to put data in the texture + * @param image Image, BufferedImage or for example + * Trade::ImageData of the same dimension count + * + * Calls setSub() with image data. + */ + template inline static void setSub(Target target, GLint mipLevel, const Math::Vector& offset, T* image); #endif }; @@ -310,9 +334,17 @@ template<> struct AbstractTexture::DataHelper<1> { glTexImage1D(static_cast(target), mipLevel, static_cast(internalFormat), dimensions.at(0), 0, static_cast(colorFormat), static_cast(type), data); } + template inline static void set(Target target, GLint mipLevel, InternalFormat internalFormat, T* image) { + set(target, mipLevel, internalFormat, image->dimensions(), image->colorFormat(), image->type(), image->data()); + } + inline static void setSub(Target target, GLint mipLevel, const Math::Vector& offset, const Math::Vector& dimensions, ColorFormat colorFormat, Type type, const void* data) { glTexSubImage1D(static_cast(target), mipLevel, offset.at(0), dimensions.at(0), static_cast(colorFormat), static_cast(type), data); } + + template inline static void setSub(Target target, GLint mipLevel, const Math::Vector& offset, T* image) { + setSub(target, mipLevel, offset, image->dimensions(), image->colorFormat(), image->type(), image->data()); + } }; template<> struct AbstractTexture::DataHelper<2> { enum class Target: GLenum { @@ -339,9 +371,17 @@ template<> struct AbstractTexture::DataHelper<2> { glTexImage2D(static_cast(target), mipLevel, static_cast(internalFormat), dimensions.at(0), dimensions.at(1), 0, static_cast(colorFormat), static_cast(type), data); } + template inline static void set(Target target, GLint mipLevel, InternalFormat internalFormat, T* image) { + set(target, mipLevel, internalFormat, image->dimensions(), image->colorFormat(), image->type(), image->data()); + } + inline static void setSub(Target target, GLint mipLevel, const Math::Vector& offset, const Math::Vector& dimensions, ColorFormat colorFormat, Type type, const void* data) { glTexSubImage2D(static_cast(target), mipLevel, offset.at(0), offset.at(1), dimensions.at(0), dimensions.at(1), static_cast(colorFormat), static_cast(type), data); } + + template inline static void setSub(Target target, GLint mipLevel, const Math::Vector& offset, T* image) { + setSub(target, mipLevel, offset, image->dimensions(), image->colorFormat(), image->type(), image->data()); + } }; template<> struct AbstractTexture::DataHelper<3> { enum class Target: GLenum { @@ -361,9 +401,17 @@ template<> struct AbstractTexture::DataHelper<3> { glTexImage3D(static_cast(target), mipLevel, static_cast(internalFormat), dimensions.at(0), dimensions.at(1), dimensions.at(2), 0, static_cast(colorFormat), static_cast(type), data); } + template inline static void set(Target target, GLint mipLevel, InternalFormat internalFormat, T* image) { + set(target, mipLevel, internalFormat, image->dimensions(), image->colorFormat(), image->type(), image->data()); + } + inline static void setSub(Target target, GLint mipLevel, const Math::Vector& offset, const Math::Vector& dimensions, ColorFormat colorFormat, Type type, const void* data) { glTexSubImage3D(static_cast(target), mipLevel, offset.at(0), offset.at(1), offset.at(2), dimensions.at(0), dimensions.at(1), dimensions.at(2), static_cast(colorFormat), static_cast(type), data); } + + template inline static void setSub(Target target, GLint mipLevel, const Math::Vector& offset, T* image) { + setSub(target, mipLevel, offset, image->dimensions(), image->colorFormat(), image->type(), image->data()); + } }; #endif diff --git a/src/BufferedImage.cpp b/src/BufferedImage.cpp new file mode 100644 index 000000000..ad9327744 --- /dev/null +++ b/src/BufferedImage.cpp @@ -0,0 +1,25 @@ +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +#include "BufferedImage.h" + +namespace Magnum { + +void BufferedImage2D::setDataFromFramebuffer(const Math::Vector2& offset) { + _buffer.bind(Buffer::Target::PixelPack); + glReadPixels(offset.at(0), offset.at(1), _dimensions.at(0), _dimensions.at(1), static_cast(_colorFormat), static_cast(_type), nullptr); +} + +} diff --git a/src/BufferedImage.h b/src/BufferedImage.h new file mode 100644 index 000000000..da2dda3ab --- /dev/null +++ b/src/BufferedImage.h @@ -0,0 +1,136 @@ +#ifndef Magnum_BufferedImage_h +#define Magnum_BufferedImage_h +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +/** @file + * @brief Class Magnum::BufferedImage + */ + +#include "AbstractTexture.h" +#include "Buffer.h" + +namespace Magnum { + +/** +@brief %Buffered image + +Class for storing image data in GPU memory. Can be replaced with Image, which +stores image data in client memory, or for example with Trade::ImageData. See +also BufferedImage2D, which has additional data updating functions. +*/ +template class BufferedImage { + BufferedImage(const BufferedImage& other) = delete; + BufferedImage(BufferedImage&& other) = delete; + BufferedImage& operator=(const BufferedImage& other) = delete; + BufferedImage& operator=(BufferedImage&& other) = delete; + + public: + const static size_t Dimensions = imageDimensions; /**< @brief Image dimension count */ + + /** + * @brief Constructor + * @param colorFormat Color format of the data. + * @param type Data type per color channel + */ + BufferedImage(AbstractTexture::ColorFormat colorFormat, Type type): _colorFormat(colorFormat), _type(type), _buffer(Buffer::Target::PixelPack) {} + + inline virtual ~BufferedImage() {} + + /** @brief %Image dimensions */ + inline Math::Vector dimensions() const { return _dimensions; } + + /** + * @brief Set image dimensions + * @param dimensions %Image dimensions + * @param usage %Image buffer usage + * + * Saves the dimensions and resizes the buffer to be able to hold + * given pixmap size. + */ + void setDimensions(const Math::Vector& dimensions, Buffer::Usage usage) { + _dimensions = dimensions; + size_t textureSize = AbstractTexture::pixelSize(AbstractTexture::ColorFormat::RGB, Type::UnsignedByte)*dimensions.product(); + _buffer.setData(Buffer::Target::PixelPack, textureSize, nullptr, usage); + } + + /** @brief Color format */ + inline AbstractTexture::ColorFormat colorFormat() const { return _colorFormat; } + + /** @brief Data type */ + inline Type type() const { return _type; } + + /** + * @brief Data + * + * Binds the buffer to @ref Buffer::Target::PixelUnpack "pixel unpack + * target" and returns nullptr, so it can be used for texture updating + * functions the same way as Image::data(). + */ + void* data() { + _buffer.bind(Buffer::Target::PixelUnpack); + return nullptr; + } + + /** + * @brief Set image data + * @param data %Image data + * + * Updates the image buffer with given data. The data are not deleted + * after filling the buffer. Note that the data must have the right + * size and type of passed data must be the same as data type passed + * in constructor. + */ + template void setData(const T* data) { + if(TypeTraits::TextureType>::glType() != _type) { + Corrade::Utility::Error() << "BufferedImage: Passed data have type" << TypeTraits::TextureType>::glType() << "but it should be" << _type; + return; + } + + size_t textureSize = AbstractTexture::pixelSize(AbstractTexture::ColorFormat::RGB, Type::UnsignedByte)*dimensions.product(); + _buffer.setSubData(Buffer::Target::PixelPack, 0, textureSize, data); + } + + protected: + AbstractTexture::ColorFormat _colorFormat; /**< @brief Color format */ + Type _type; /**< @brief Data type per color channel */ + Math::Vector _dimensions; /**< @brief %Image dimensions */ + Buffer _buffer; /**< @brief %Image buffer */ +}; + +/** @brief One-dimensional buffered image */ +typedef BufferedImage<1> BufferedImage1D; + +/** @brief Two-dimensional buffered image */ +class BufferedImage2D: public BufferedImage<2> { + public: + /** @copydoc BufferedImage::BufferedImage */ + inline BufferedImage2D(AbstractTexture::ColorFormat colorFormat, Type type): BufferedImage(colorFormat, type) {} + + /** + * @brief Set image data from current framebuffer + * @param offset Offset of the pixamp to read + * + * Reads pixmap from given offset with already set dimensions. + */ + void setDataFromFramebuffer(const Math::Vector2& offset); +}; + +/** @brief Three-dimensional buffered image */ +typedef BufferedImage<3> BufferedImage3D; + +} + +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2d09f0a08..d19f11ebf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,7 +11,9 @@ set(Magnum_SRCS Object.cpp AbstractTexture.cpp AbstractShaderProgram.cpp + BufferedImage.cpp Camera.cpp + Image.cpp IndexedMesh.cpp Light.cpp Mesh.cpp diff --git a/src/CubeMapTexture.h b/src/CubeMapTexture.h index f9a0d76a6..68edc9542 100644 --- a/src/CubeMapTexture.h +++ b/src/CubeMapTexture.h @@ -65,24 +65,26 @@ class CubeMapTexture: public Texture2D { inline CubeMapTexture(GLint layer = 0): Texture(layer, Target::CubeMap) {} template inline void setData(GLint mipLevel, InternalFormat internalFormat, const Math::Vector& _dimensions, ColorFormat colorFormat, const T* data) = delete; - void setData(GLint mipLevel, InternalFormat internalFormat, const Trade::ImageData* image) = delete; + template void setData(GLint mipLevel, InternalFormat internalFormat, T* image) = delete; template inline void setSubData(GLint mipLevel, const Math::Vector& offset, const Math::Vector& _dimensions, ColorFormat colorFormat, const T* data) = delete; - void setSubData(GLint mipLevel, const Math::Vector& offset, const Trade::ImageData* image) = delete; + template void setSubData(GLint mipLevel, const Math::Vector& offset, T* image) = delete; /** * @copydoc Texture::setData(GLint, InternalFormat, const Math::Vector&, ColorFormat, const T*) * @param coordinate Coordinate */ template inline void setData(Coordinate coordinate, GLint mipLevel, InternalFormat internalFormat, const Math::Vector& _dimensions, ColorFormat colorFormat, const T* data) { - setData(coordinate, mipLevel, internalFormat, _dimensions, colorFormat, TypeTraits::TextureType>::glType(), data); + bind(); + DataHelper::set(static_cast(coordinate), mipLevel, internalFormat, _dimensions, colorFormat, TypeTraits::TextureType>::glType(), data); } /** - * @copydetails Texture::setData(GLint, InternalFormat, const Trade::ImageData*) + * @copydetails Texture::setData(GLint, InternalFormat, T*) * @param coordinate Coordinate */ - inline void setData(Coordinate coordinate, GLint mipLevel, InternalFormat internalFormat, const Trade::ImageData* image) { - setData(coordinate, mipLevel, internalFormat, image->dimensions(), image->colorFormat(), image->type(), image->data()); + template inline void setData(Coordinate coordinate, GLint mipLevel, InternalFormat internalFormat, T* image) { + bind(); + DataHelper::set(static_cast(coordinate), mipLevel, internalFormat, image); } /** @@ -90,26 +92,17 @@ class CubeMapTexture: public Texture2D { * @param coordinate Coordinate */ template inline void setSubData(Coordinate coordinate, GLint mipLevel, const Math::Vector& offset, const Math::Vector& _dimensions, ColorFormat colorFormat, const T* data) { - setSubData(coordinate, mipLevel, offset, _dimensions, colorFormat, TypeTraits::TextureType>::glType(), data); + bind(); + DataHelper::setSub(static_cast(coordinate), mipLevel, offset, _dimensions, colorFormat, TypeTraits::TextureType>::glType(), data); } /** - * @copydoc Texture::setSubData(GLint, const Math::Vector&, const Trade::ImageData*) + * @copydoc Texture::setSubData(GLint, const Math::Vector&, T*) * @param coordinate Coordinate */ - inline void setSubData(Coordinate coordinate, GLint mipLevel, const Math::Vector& offset, const Trade::ImageData* image) { - setSubData(coordinate, mipLevel, offset, image->dimensions(), image->colorFormat(), image->type(), image->data()); - } - - private: - inline void setData(Coordinate coordinate, GLint mipLevel, InternalFormat internalFormat, const Math::Vector& _dimensions, ColorFormat colorFormat, Type type, const void* data) { - bind(); - DataHelper::set(static_cast(coordinate), mipLevel, internalFormat, _dimensions, colorFormat, type, data); - } - - inline void setSubData(Coordinate coordinate, GLint mipLevel, const Math::Vector& offset, const Math::Vector& dimensions, ColorFormat colorFormat, Type type, const void* data) { + template inline void setSubData(Coordinate coordinate, GLint mipLevel, const Math::Vector& offset, const T* image) { bind(); - DataHelper::setSub(static_cast(coordinate), mipLevel, offset, dimensions, colorFormat, type, data); + DataHelper::setSub(static_cast(coordinate), mipLevel, offset, image); } }; diff --git a/src/Image.cpp b/src/Image.cpp new file mode 100644 index 000000000..3de3e738e --- /dev/null +++ b/src/Image.cpp @@ -0,0 +1,24 @@ +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +#include "Image.h" + +namespace Magnum { + +void Image2D::setDataFromFramebuffer(const Math::Vector2& offset) { + glReadPixels(offset.at(0), offset.at(1), _dimensions.at(0), _dimensions.at(1), static_cast(_colorFormat), static_cast(_type), _data); +} + +} diff --git a/src/Image.h b/src/Image.h new file mode 100644 index 000000000..856c24eed --- /dev/null +++ b/src/Image.h @@ -0,0 +1,141 @@ +#ifndef Magnum_Image_h +#define Magnum_Image_h +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +/** @file + * @brief Class Magnum::Image + */ + +#include "AbstractTexture.h" + +namespace Magnum { + +/** +@brief %Image + +Class for storing image data on client memory. Can be replaced with +BufferedImage, which stores image data in GPU memory, or for example with +Trade::ImageData. See also Image2D, which has additional data updating +functions. +*/ +template class Image { + Image(const Image& other) = delete; + Image(Image&& other) = delete; + Image& operator=(const Image& other) = delete; + Image& operator=(Image&& other) = delete; + + public: + const static size_t Dimensions = imageDimensions; /**< @brief Image dimension count */ + + /** + * @brief Constructor + * @param colorFormat Color format of passed data. Data size + * per color channel is detected from format of passed data array. + * @param dimensions %Image dimensions + * @param data %Image data with proper size + * + * Note that the image data are not copied on construction, but they + * are deleted on class destruction. + */ + template inline Image(AbstractTexture::ColorFormat colorFormat, const Math::Vector& dimensions, T* data): _colorFormat(colorFormat), _type(TypeTraits::TextureType>::glType()), _dimensions(dimensions), _data(data) {} + + /** + * @brief Constructor + * @param colorFormat Color format of passed data + * @param type Data type per color channel + * + * Dimensions and data pointer are are set to zero, call + * setDimensions() and setData() to fill the image with data. + */ + inline Image(AbstractTexture::ColorFormat colorFormat, Type type): _colorFormat(colorFormat), _type(type), _data(nullptr) {} + + /** @brief Destructor */ + inline virtual ~Image() { delete[] _data; } + + /** @brief %Image dimensions */ + inline const Math::Vector& dimensions() const { return _dimensions; } + + /** + * @brief Set image dimensions + * @param dimensions %Image dimensions + * + * Saves the dimensions and deletes the internal data array. + */ + inline void setDimensions(const Math::Vector2& dimensions) { + _dimensions = dimensions; + delete _data; + _data = 0; + } + + /** @brief Color format */ + inline AbstractTexture::ColorFormat colorFormat() const { return _colorFormat; } + + /** @brief Data type */ + inline Type type() const { return _type; } + + /** @brief Pointer to raw data */ + inline const void* data() const { return _data; } + + /** + * @brief Set image data + * @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. Also the + * type of passed data must be the same as data type passed in + * constructor. + */ + template void setData(const T* data) { + if(TypeTraits::TextureType>::glType() != _type) { + Corrade::Utility::Error() << "Image: Passed data have type" << TypeTraits::TextureType>::glType() << "but it should be" << _type; + return; + } + + delete _data; + _data = reinterpret_cast(data); + } + + protected: + AbstractTexture::ColorFormat _colorFormat; /**< @brief Color format */ + Type _type; /**< @brief Data type per color channel */ + Math::Vector _dimensions; /**< @brief %Image dimensions */ + char* _data; /**< @brief %Image data */ +}; + +/** @brief One-dimensional image */ +typedef Image<1> Image1D; + +/** @brief Two-dimensional image */ +class Image2D: public Image<2> { + public: + /** @copydoc Image::Image */ + inline Image2D(AbstractTexture::ColorFormat colorFormat, Type type): Image(colorFormat, type) {} + + /** + * @brief Set image data from current framebuffer + * @param offset Offset of the pixamp to read + * + * Reads pixmap from given offset with already set dimensions. + */ + void setDataFromFramebuffer(const Math::Vector2& offset); +}; + +/** @brief Three-dimensional image */ +typedef Image<3> Image3D; + +} + +#endif diff --git a/src/Texture.h b/src/Texture.h index 83c2243cb..afee56d86 100644 --- a/src/Texture.h +++ b/src/Texture.h @@ -99,14 +99,15 @@ template class Texture: public AbstractTexture { * @brief Set texture data from image * @param mipLevel Mip level * @param internalFormat Internal texture format - * @param image Image + * @param image Image, BufferedImage or for example + * Trade::ImageData of the same dimension count * * Sets texture data from given image. The image is not deleted * afterwards. */ - inline void setData(GLint mipLevel, InternalFormat internalFormat, const Trade::ImageData* image) { + template inline void setData(GLint mipLevel, InternalFormat internalFormat, T* image) { bind(); - DataHelper::set(target, mipLevel, internalFormat, image->dimensions(), image->colorFormat(), image->type(), image->data()); + DataHelper::set(target, mipLevel, internalFormat, image); } /** @@ -130,14 +131,15 @@ template class Texture: public AbstractTexture { * @brief Set texture subdata from image * @param mipLevel Mip level * @param offset Offset where to put data in the texture - * @param image Image + * @param image Image, BufferedImage or for example + * Trade::ImageData of the same dimension count * * Sets texture subdata from given image. The image is not deleted * afterwards. */ - inline void setSubData(GLint mipLevel, const Math::Vector& offset, const Trade::ImageData* image) { + template inline void setSubData(GLint mipLevel, const Math::Vector& offset, T* image) { bind(); - DataHelper::setSub(target, mipLevel, offset, image->dimensions(), image->colorFormat(), image->type(), image->data()); + DataHelper::setSub(target, mipLevel, offset, image); } private: diff --git a/src/Trade/ImageData.h b/src/Trade/ImageData.h index 1c11a94f1..eff705d28 100644 --- a/src/Trade/ImageData.h +++ b/src/Trade/ImageData.h @@ -27,7 +27,7 @@ namespace Magnum { namespace Trade { @brief %Image Provides access to image data and additional information about data type and -dimensions. +dimensions. Can be used in the same situations as Image and BufferedImage. */ template class ImageData { ImageData(const ImageData& other) = delete; @@ -40,15 +40,15 @@ template class ImageData { /** * @brief Constructor - * @param dimensions %Image dimensions * @param colorFormat Color format of passed data. Data size * per color channel is detected from format of passed data array. + * @param dimensions %Image dimensions * @param data %Image data * * @attention Note that the image data are not copied on construction, * but they are deleted on class destruction. */ - template inline ImageData(const Math::Vector& dimensions, AbstractTexture::ColorFormat colorFormat, const T* data): _dimensions(dimensions), _colorFormat(colorFormat), _type(TypeTraits::TextureType>::glType()), _data(reinterpret_cast(data)) {} + template inline ImageData(AbstractTexture::ColorFormat colorFormat, const Math::Vector& dimensions, const T* data): _colorFormat(colorFormat), _type(TypeTraits::TextureType>::glType()), _dimensions(dimensions), _data(reinterpret_cast(data)) {} /** @brief Destructor */ inline virtual ~ImageData() { delete[] _data; } @@ -66,9 +66,9 @@ template class ImageData { inline const void* data() const { return _data; } private: - Math::Vector _dimensions; AbstractTexture::ColorFormat _colorFormat; Type _type; + Math::Vector _dimensions; const char* _data; };