diff --git a/doc/opengl-mapping.dox b/doc/opengl-mapping.dox index e2cc645e2..82c3711fc 100644 --- a/doc/opengl-mapping.dox +++ b/doc/opengl-mapping.dox @@ -209,7 +209,7 @@ OpenGL function | Matching API @fn_gl{GetTexImage}, \n `glGetnTexImage()`, \n @fn_gl_extension{GetnTexImage,ARB,robustness}, \n `glGetTextureImage()`, \n @fn_gl_extension{GetTextureImage,EXT,direct_state_access} | @ref Texture::image(), \n @ref TextureArray::image(), \n @ref CubeMapTexture::image(), \n @ref CubeMapTextureArray::image(), \n @ref RectangleTexture::image() @fn_gl{GetTexLevelParameter}, \n `glGetTextureLevelParameter()`, \n @fn_gl_extension{GetTextureLevelParameter,EXT,direct_state_access} | @ref Texture::imageSize(), \n @ref TextureArray::imageSize(), \n @ref CubeMapTexture::imageSize(), \n @ref CubeMapTextureArray::imageSize(), \n @ref RectangleTexture::imageSize() @fn_gl{GetTexParameter}, \n `glGetTextureParameter()`, \n @fn_gl_extension{GetTextureParameter,EXT,direct_state_access} | | -@fn_gl{GetTextureSubImage} | | +@fn_gl{GetTextureSubImage} | @ref CubeMapTexture::image() @fn_gl{GetTransformFeedback} | not queryable, @ref TransformFeedback::attachBuffer() and @ref TransformFeedback::attachBuffers() setters only @fn_gl{GetTransformFeedbackVarying} | not queryable, @ref AbstractShaderProgram::setTransformFeedbackOutputs() setter only @fn_gl{GetUniform}, \n `glGetnUniform()`, \n @fn_gl_extension{GetnUniform,ARB,robustness} | not queryable, @ref AbstractShaderProgram::setUniform() setter only diff --git a/src/Magnum/CubeMapTexture.cpp b/src/Magnum/CubeMapTexture.cpp index cfcc7a05c..18f9dd216 100644 --- a/src/Magnum/CubeMapTexture.cpp +++ b/src/Magnum/CubeMapTexture.cpp @@ -56,6 +56,35 @@ Vector2i CubeMapTexture::imageSize(const Int level) { #endif #ifndef MAGNUM_TARGET_GLES +void CubeMapTexture::image(const Int level, Image3D& image) { + const Vector3i size{imageSize(level), 6}; + const std::size_t dataSize = image.dataSize(size); + char* data = new char[dataSize]; + Buffer::unbindInternal(Buffer::TargetHint::PixelPack); + glGetTextureImage(_id, level, GLenum(image.format()), GLenum(image.type()), dataSize, data); + image.setData(image.format(), image.type(), size, data); +} + +Image3D CubeMapTexture::image(const Int level, Image3D&& image) { + this->image(level, image); + return std::move(image); +} + +void CubeMapTexture::image(const Int level, BufferImage3D& image, const BufferUsage usage) { + const Vector3i size{imageSize(level), 6}; + const std::size_t dataSize = image.dataSize(size); + if(image.size() != size) + image.setData(image.format(), image.type(), size, nullptr, usage); + + image.buffer().bindInternal(Buffer::TargetHint::PixelPack); + glGetTextureImage(_id, level, GLenum(image.format()), GLenum(image.type()), dataSize, nullptr); +} + +BufferImage3D CubeMapTexture::image(const Int level, BufferImage3D&& image, const BufferUsage usage) { + this->image(level, image, usage); + return std::move(image); +} + void CubeMapTexture::image(const Coordinate coordinate, const Int level, Image2D& image) { const Vector2i size = imageSize(level); const std::size_t dataSize = image.dataSize(size); @@ -84,6 +113,18 @@ BufferImage2D CubeMapTexture::image(const Coordinate coordinate, const Int level this->image(coordinate, level, image, usage); return std::move(image); } + +CubeMapTexture& CubeMapTexture::setSubImage(const Int level, const Vector3i& offset, const ImageReference3D& image) { + Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack); + glTextureSubImage3D(_id, level, offset.x(), offset.y(), offset.z(), image.size().x(), image.size().y(), image.size().z(), GLenum(image.format()), GLenum(image.type()), image.data()); + return *this; +} + +CubeMapTexture& CubeMapTexture::setSubImage(const Int level, const Vector3i& offset, BufferImage3D& image) { + image.buffer().bindInternal(Buffer::TargetHint::PixelUnpack); + glTextureSubImage3D(_id, level, offset.x(), offset.y(), offset.z(), image.size().x(), image.size().y(), image.size().z(), GLenum(image.format()), GLenum(image.type()), nullptr); + return *this; +} #endif CubeMapTexture& CubeMapTexture::setSubImage(const Coordinate coordinate, const Int level, const Vector2i& offset, const ImageReference2D& image) { diff --git a/src/Magnum/CubeMapTexture.h b/src/Magnum/CubeMapTexture.h index 889f91c78..7fb2bf56c 100644 --- a/src/Magnum/CubeMapTexture.h +++ b/src/Magnum/CubeMapTexture.h @@ -378,6 +378,47 @@ class MAGNUM_EXPORT CubeMapTexture: public AbstractTexture { #endif #ifndef MAGNUM_TARGET_GLES + /** + * @brief Read given mip level of texture to image + * + * Image parameters like format and type of pixel data are taken from + * given image, image size is taken from the texture using + * @ref imageSize(). + * @see @fn_gl2{GetTextureLevelParameter,GetTexLevelParameter} with + * @def_gl{TEXTURE_WIDTH}, @def_gl{TEXTURE_HEIGHT}, then + * @fn_gl{GetTextureImage} + * @requires_gl45 Extension @extension{ARB,direct_state_access} + * @requires_gl Texture image queries are not available in OpenGL ES. + */ + void image(Int level, Image3D& image); + + /** @overload + * + * Convenience alternative to the above, example usage: + * @code + * Image3D image = texture.image(0, {ColorFormat::RGBA, ColorType::UnsignedByte}); + * @endcode + */ + Image3D image(Int level, Image3D&& image); + + /** + * @brief Read given mip level of texture to buffer image + * + * See @ref image(Int, Image3D&) for more information. + * @requires_gl45 Extension @extension{ARB,direct_state_access} + * @requires_gl Texture image queries are not available in OpenGL ES. + */ + void image(Int level, BufferImage3D& image, BufferUsage usage); + + /** @overload + * + * Convenience alternative to the above, example usage: + * @code + * BufferImage3D image = texture.image(0, {ColorFormat::RGBA, ColorType::UnsignedByte}, BufferUsage::StaticRead); + * @endcode + */ + BufferImage3D image(Int level, BufferImage3D&& image, BufferUsage usage); + /** * @brief Read given mip level and coordinate of texture to image * @@ -473,6 +514,39 @@ class MAGNUM_EXPORT CubeMapTexture: public AbstractTexture { } #endif + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Set image subdata + * @param level Mip level + * @param offset Offset where to put data in the texture + * @param image @ref Image, @ref ImageReference or + * @ref Trade::ImageData of the same dimension count + * @return Reference to self (for method chaining) + * + * @see @ref setStorage(), @fn_gl2{TextureSubImage3D,TexSubImage3D} + * @requires_gl45 Extension @extension{ARB,direct_state_access} + * @requires_gl In OpenGL ES you need to set image for each face + * separately. + */ + CubeMapTexture& setSubImage(Int level, const Vector3i& offset, const ImageReference3D& image); + + /** @overload + * @requires_gl45 Extension @extension{ARB,direct_state_access} + * @requires_gl In OpenGL ES you need to set image for each face + * separately. + */ + CubeMapTexture& setSubImage(Int level, const Vector3i& offset, BufferImage3D& image); + + /** @overload + * @requires_gl45 Extension @extension{ARB,direct_state_access} + * @requires_gl In OpenGL ES you need to set image for each face + * separately. + */ + CubeMapTexture& setSubImage(Int level, const Vector3i& offset, BufferImage3D&& image) { + return setSubImage(level, offset, image); + } + #endif + /** * @copybrief Texture::setSubImage() * @return Reference to self (for method chaining) diff --git a/src/Magnum/Test/CubeMapTextureGLTest.cpp b/src/Magnum/Test/CubeMapTextureGLTest.cpp index 4030a0761..01954ecb2 100644 --- a/src/Magnum/Test/CubeMapTextureGLTest.cpp +++ b/src/Magnum/Test/CubeMapTextureGLTest.cpp @@ -61,6 +61,10 @@ struct CubeMapTextureGLTest: AbstractOpenGLTester { void storage(); + #ifndef MAGNUM_TARGET_GLES + void imageFull(); + void imageFullBuffer(); + #endif void image(); #ifndef MAGNUM_TARGET_GLES2 void imageBuffer(); @@ -98,6 +102,10 @@ CubeMapTextureGLTest::CubeMapTextureGLTest() { &CubeMapTextureGLTest::storage, + #ifndef MAGNUM_TARGET_GLES + &CubeMapTextureGLTest::imageFull, + &CubeMapTextureGLTest::imageFullBuffer, + #endif &CubeMapTextureGLTest::image, #ifndef MAGNUM_TARGET_GLES2 &CubeMapTextureGLTest::imageBuffer, @@ -276,6 +284,79 @@ void CubeMapTextureGLTest::storage() { #endif } +namespace { + constexpr UnsignedByte Data[] = { 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, + + 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, + + 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, + + 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, + + 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, + + 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, + 0x5c, 0x5d, 0x5e, 0x5f }; +} + +#ifndef MAGNUM_TARGET_GLES +void CubeMapTextureGLTest::imageFull() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::direct_state_access::string() + std::string(" is not supported.")); + + CubeMapTexture texture; + texture.setStorage(1, TextureFormat::RGBA8, Vector2i{2, 2}) + .setSubImage(0, {}, ImageReference3D{ColorFormat::RGBA, ColorType::UnsignedByte, Vector3i{2, 2, 6}, Data}); + + MAGNUM_VERIFY_NO_ERROR(); + + Image3D image = texture.image(0, {ColorFormat::RGBA, ColorType::UnsignedByte}); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), Vector3i(2, 2, 6)); + CORRADE_COMPARE_AS(std::vector(image.data(), image.data()+image.pixelSize()*image.size().product()), + std::vector(Data, Data+96), TestSuite::Compare::Container); +} + +void CubeMapTextureGLTest::imageFullBuffer() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::direct_state_access::string() + std::string(" is not supported.")); + + CubeMapTexture texture; + texture.setStorage(1, TextureFormat::RGBA8, Vector2i{2}) + .setSubImage(0, {}, BufferImage3D{ColorFormat::RGBA, ColorType::UnsignedByte, Vector3i{2, 2, 6}, Data, BufferUsage::StaticDraw}); + + MAGNUM_VERIFY_NO_ERROR(); + + BufferImage3D image = texture.image(0, {ColorFormat::RGBA, ColorType::UnsignedByte}, BufferUsage::StaticRead); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), Vector3i(2, 2, 6)); + const auto imageData = image.buffer().data(); + CORRADE_COMPARE_AS(std::vector(imageData.begin(), imageData.end()), + std::vector(Data, Data+96), TestSuite::Compare::Container); +} +#endif + void CubeMapTextureGLTest::image() { constexpr UnsignedByte data[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,