diff --git a/doc/changelog.dox b/doc/changelog.dox index 6772db35e..0b697cc6e 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -491,6 +491,8 @@ See also: easier ability to download the resulting image on OpenGL ES platforms; the @ref magnum-distancefieldconverter "magnum-distancefieldconverter" utility thus now compiles and works on OpenGL ES 3+ as well +- Added a @ref TextureTools::DistanceFieldGL::operator()() overload taking a + @ref GL::TextureArray as an output @subsubsection changelog-latest-new-trade Trade library diff --git a/src/Magnum/TextureTools/DistanceFieldGL.cpp b/src/Magnum/TextureTools/DistanceFieldGL.cpp index 7e0ed9b28..9ad418bb9 100644 --- a/src/Magnum/TextureTools/DistanceFieldGL.cpp +++ b/src/Magnum/TextureTools/DistanceFieldGL.cpp @@ -237,4 +237,19 @@ void DistanceFieldGL::operator()(GL::Texture2D& input, GL::Texture2D& output, co } #endif +#ifndef MAGNUM_TARGET_GLES2 +void DistanceFieldGL::operator()(GL::Texture2D& input, GL::Texture2DArray& output, const Int layer, const Range2Di& rectangle, const Vector2i& imageSize) { + GL::Framebuffer framebuffer{rectangle}; + framebuffer.attachTextureLayer(GL::Framebuffer::ColorAttachment{0}, output, 0, layer); + + operator()(input, framebuffer, rectangle, imageSize); +} + +#ifndef MAGNUM_TARGET_GLES +void DistanceFieldGL::operator()(GL::Texture2D& input, GL::Texture2DArray& output, const Int layer, const Range2Di& rectangle) { + return operator()(input, output, layer, rectangle, {}); +} +#endif +#endif + }} diff --git a/src/Magnum/TextureTools/DistanceFieldGL.h b/src/Magnum/TextureTools/DistanceFieldGL.h index 18509b8e1..18227b1de 100644 --- a/src/Magnum/TextureTools/DistanceFieldGL.h +++ b/src/Magnum/TextureTools/DistanceFieldGL.h @@ -296,6 +296,40 @@ class MAGNUM_TEXTURETOOLS_EXPORT DistanceFieldGL { #endif #endif + #ifndef MAGNUM_TARGET_GLES2 + /** + * @brief Calculate distance field to a texture array layer + * @param input Input texture + * @param output Output texture + * @param layer Layer in the output where to render + * @param rectangle Rectangle in the output where to render + * @param imageSize Input texture size. Mandatory on OpenGL ES and + * WebGL, on desktop GL if left at default the size is internally + * queried using @ref GL::Texture2D::imageSize() instead. + * @m_since_latest + * + * Convenience variant of @ref operator()(GL::Texture2D&, GL::Framebuffer&, const Range2Di&, const Vector2i&) + * that creates a temporary framebuffer with @p output @p layer + * attached and destroys it again after the operation. + * @requires_gl30 Extension @gl_extension{EXT,texture_array} + * @requires_gles30 Texture arrays are not available in OpenGL ES 2.0. + * @requires_webgl20 Texture arrays are not available in WebGL 1.0. + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + void operator()(GL::Texture2D& input, GL::Texture2DArray& output, Int layer, const Range2Di& rectangle, const Vector2i& imageSize + #ifndef MAGNUM_TARGET_GLES + = {} + #endif + ); + #else + /* To avoid having to include Vector2 */ + void operator()(GL::Texture2D& input, GL::Texture2DArray& output, Int layer, const Range2Di& rectangle, const Vector2i& imageSize); + #ifndef MAGNUM_TARGET_GLES + void operator()(GL::Texture2D& input, GL::Texture2DArray& output, Int layer, const Range2Di& rectangle); + #endif + #endif + #endif + private: struct State; Containers::Pointer _state; diff --git a/src/Magnum/TextureTools/Test/DistanceFieldGLTest.cpp b/src/Magnum/TextureTools/Test/DistanceFieldGLTest.cpp index ebcbed68e..e5f47c3fe 100644 --- a/src/Magnum/TextureTools/Test/DistanceFieldGLTest.cpp +++ b/src/Magnum/TextureTools/Test/DistanceFieldGLTest.cpp @@ -47,6 +47,9 @@ #include "Magnum/GL/OpenGLTester.h" #include "Magnum/GL/PixelFormat.h" #include "Magnum/GL/Texture.h" +#ifndef MAGNUM_TARGET_GLES2 +#include "Magnum/GL/TextureArray.h" +#endif #include "Magnum/GL/TextureFormat.h" #include "Magnum/TextureTools/DistanceFieldGL.h" #include "Magnum/Trade/AbstractImporter.h" @@ -81,34 +84,45 @@ using namespace Math::Literals; const struct { const char* name; - bool framebuffer, implicitOutputSize; + bool framebuffer, implicitOutputSize, array; + Int layer; Vector2i size; Vector2i offset; bool flipX, flipY; } RunData[]{ {"texture output", - false, false, {64, 64}, {}, false, false}, + false, false, false, 0, {64, 64}, {}, false, false}, {"texture output, flipped on X", - false, false, {64, 64}, {}, true, false}, + false, false, false, 0, {64, 64}, {}, true, false}, {"texture output, flipped on Y", - false, false, {64, 64}, {}, false, true}, + false, false, false, 0, {64, 64}, {}, false, true}, {"texture output, with offset", - false, false, {128, 96}, {64, 32}, false, false}, + false, false, false, 0, {128, 96}, {64, 32}, false, false}, #ifndef MAGNUM_TARGET_GLES {"texture output with implicit size", - false, true, {64, 64}, {}, false, false}, + false, true, false, 0, {64, 64}, {}, false, false}, + #endif + #ifndef MAGNUM_TARGET_GLES2 + {"texture array output, first layer", + false, false, true, 0, {64, 64}, {}, false, false}, + {"texture array output, arbitrary layer", + false, false, true, 3, {64, 64}, {}, false, false}, + #ifndef MAGNUM_TARGET_GLES + {"texture array output with implicit size, arbitrary layer", + false, true, true, 3, {64, 64}, {}, false, false}, + #endif #endif {"framebuffer output", - true, false, {64, 64}, {}, false, false}, + true, false, false, 0, {64, 64}, {}, false, false}, {"framebuffer output, flipped on X", - true, false, {64, 64}, {}, true, false}, + true, false, false, 0, {64, 64}, {}, true, false}, {"framebuffer output, flipped on Y", - true, false, {64, 64}, {}, false, true}, + true, false, false, 0, {64, 64}, {}, false, true}, {"framebuffer output, with offset", - true, false, {128, 96}, {64, 32}, false, false}, + true, false, false, 0, {128, 96}, {64, 32}, false, false}, #ifndef MAGNUM_TARGET_GLES {"framebuffer output with implicit size", - true, true, {64, 64}, {}, false, false}, + true, true, false, 0, {64, 64}, {}, false, false}, #endif }; @@ -262,16 +276,34 @@ void DistanceFieldGLTest::run() { #endif const GL::PixelType outputPixelType = GL::PixelType::UnsignedByte; - GL::Texture2D outputTexture; - outputTexture.setMinificationFilter(GL::SamplerFilter::Nearest, GL::SamplerMipmap::Base) - .setMagnificationFilter(GL::SamplerFilter::Nearest) - .setStorage(1, outputTextureFormat, data.size); - - /* Fill the texture with some data to verify they don't affect the output - and aren't accidentally overwritten when running on just a - subrectangle */ - outputTexture.setSubImage(0, {}, ImageView2D{outputPixelFormat, outputPixelType, data.size, - Containers::Array{DirectInit, std::size_t(data.size.product()*GL::pixelFormatSize(outputPixelFormat, outputPixelType)), '\x66'}}); + GL::Texture2D outputTexture{NoCreate}; + #ifndef MAGNUM_TARGET_GLES2 + GL::Texture2DArray outputTextureArray{NoCreate}; + if(data.array) { + outputTextureArray = GL::Texture2DArray{}; + outputTextureArray.setMinificationFilter(GL::SamplerFilter::Nearest, GL::SamplerMipmap::Base) + .setMagnificationFilter(GL::SamplerFilter::Nearest) + .setStorage(1, outputTextureFormat, {data.size, data.layer + 1}); + + /* Fill the texture with some data to verify they don't affect the + output and aren't accidentally overwritten when running on just a + subrectangle */ + outputTextureArray.setSubImage(0, {}, ImageView2D{outputPixelFormat, outputPixelType, data.size, + Containers::Array{DirectInit, std::size_t(data.size.product()*(data.layer + 1)*GL::pixelFormatSize(outputPixelFormat, outputPixelType)), '\x66'}}); + } else + #endif + { + outputTexture = GL::Texture2D{}; + outputTexture.setMinificationFilter(GL::SamplerFilter::Nearest, GL::SamplerMipmap::Base) + .setMagnificationFilter(GL::SamplerFilter::Nearest) + .setStorage(1, outputTextureFormat, data.size); + + /* Fill the texture with some data to verify they don't affect the + output and aren't accidentally overwritten when running on just a + subrectangle */ + outputTexture.setSubImage(0, {}, ImageView2D{outputPixelFormat, outputPixelType, data.size, + Containers::Array{DirectInit, std::size_t(data.size.product()*GL::pixelFormatSize(outputPixelFormat, outputPixelType)), '\x66'}}); + } GL::Framebuffer outputFramebuffer{NoCreate}; if(data.framebuffer) { @@ -296,7 +328,21 @@ void DistanceFieldGLTest::run() { distanceField(input, outputFramebuffer, Range2Di::fromSize(data.offset, Vector2i{64}), inputImage->size()); - } else { + } + #ifndef MAGNUM_TARGET_GLES2 + else if(data.array) { + #ifndef MAGNUM_TARGET_GLES + if(data.implicitOutputSize) + distanceField(input, outputTextureArray, data.layer, + Range2Di::fromSize(data.offset, Vector2i{64})); + else + #endif + distanceField(input, outputTextureArray, data.layer, + Range2Di::fromSize(data.offset, Vector2i{64}), + inputImage->size()); + } else + #endif + { #ifndef MAGNUM_TARGET_GLES if(data.implicitOutputSize) distanceField(input, outputTexture, @@ -327,14 +373,24 @@ void DistanceFieldGLTest::run() { /* Verify that the other data weren't overwritten if processing just a subrange -- it should still have the original data kept */ if(data.offset.product()) { - DebugTools::textureSubImage(outputTexture, 0, Range2Di::fromSize({}, Vector2i{1}), *actualOutputImage); + #ifndef MAGNUM_TARGET_GLES2 + if(data.array) + DebugTools::textureSubImage(outputTextureArray, 0, data.layer, Range2Di::fromSize({}, Vector2i{1}), *actualOutputImage); + else + #endif + DebugTools::textureSubImage(outputTexture, 0, Range2Di::fromSize({}, Vector2i{1}), *actualOutputImage); MAGNUM_VERIFY_NO_GL_ERROR(); CORRADE_COMPARE(actualOutputImage->data()[0], '\x66'); } - DebugTools::textureSubImage(outputTexture, 0, Range2Di::fromSize(data.offset, Vector2i{64}), *actualOutputImage); + #ifndef MAGNUM_TARGET_GLES2 + if(data.array) + DebugTools::textureSubImage(outputTextureArray, 0, data.layer, Range2Di::fromSize(data.offset, Vector2i{64}), *actualOutputImage); + else + #endif + DebugTools::textureSubImage(outputTexture, 0, Range2Di::fromSize(data.offset, Vector2i{64}), *actualOutputImage); MAGNUM_VERIFY_NO_GL_ERROR();