Browse Source

TextureTools: DistanceFieldGL overload taking texture array as output.

It just binds a layer of it to a framebuffer internally so no shader
changes or extra construction flags are needed. Originally I thought
about making the input an array as well, but ultimately that just
doesn't make sense -- the processing would need to be done slice by
slice anyway and you don't want to allocate the whole excessively sized
texture just for it to be used once, and only a part of it every time.
pull/674/head
Vladimír Vondruš 1 year ago
parent
commit
3cd8b9021b
  1. 2
      doc/changelog.dox
  2. 15
      src/Magnum/TextureTools/DistanceFieldGL.cpp
  3. 34
      src/Magnum/TextureTools/DistanceFieldGL.h
  4. 104
      src/Magnum/TextureTools/Test/DistanceFieldGLTest.cpp

2
doc/changelog.dox

@ -491,6 +491,8 @@ See also:
easier ability to download the resulting image on OpenGL ES platforms; easier ability to download the resulting image on OpenGL ES platforms;
the @ref magnum-distancefieldconverter "magnum-distancefieldconverter" the @ref magnum-distancefieldconverter "magnum-distancefieldconverter"
utility thus now compiles and works on OpenGL ES 3+ as well 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 @subsubsection changelog-latest-new-trade Trade library

15
src/Magnum/TextureTools/DistanceFieldGL.cpp

@ -237,4 +237,19 @@ void DistanceFieldGL::operator()(GL::Texture2D& input, GL::Texture2D& output, co
} }
#endif #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
}} }}

34
src/Magnum/TextureTools/DistanceFieldGL.h

@ -296,6 +296,40 @@ class MAGNUM_TEXTURETOOLS_EXPORT DistanceFieldGL {
#endif #endif
#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: private:
struct State; struct State;
Containers::Pointer<State> _state; Containers::Pointer<State> _state;

104
src/Magnum/TextureTools/Test/DistanceFieldGLTest.cpp

@ -47,6 +47,9 @@
#include "Magnum/GL/OpenGLTester.h" #include "Magnum/GL/OpenGLTester.h"
#include "Magnum/GL/PixelFormat.h" #include "Magnum/GL/PixelFormat.h"
#include "Magnum/GL/Texture.h" #include "Magnum/GL/Texture.h"
#ifndef MAGNUM_TARGET_GLES2
#include "Magnum/GL/TextureArray.h"
#endif
#include "Magnum/GL/TextureFormat.h" #include "Magnum/GL/TextureFormat.h"
#include "Magnum/TextureTools/DistanceFieldGL.h" #include "Magnum/TextureTools/DistanceFieldGL.h"
#include "Magnum/Trade/AbstractImporter.h" #include "Magnum/Trade/AbstractImporter.h"
@ -81,34 +84,45 @@ using namespace Math::Literals;
const struct { const struct {
const char* name; const char* name;
bool framebuffer, implicitOutputSize; bool framebuffer, implicitOutputSize, array;
Int layer;
Vector2i size; Vector2i size;
Vector2i offset; Vector2i offset;
bool flipX, flipY; bool flipX, flipY;
} RunData[]{ } RunData[]{
{"texture output", {"texture output",
false, false, {64, 64}, {}, false, false}, false, false, false, 0, {64, 64}, {}, false, false},
{"texture output, flipped on X", {"texture output, flipped on X",
false, false, {64, 64}, {}, true, false}, false, false, false, 0, {64, 64}, {}, true, false},
{"texture output, flipped on Y", {"texture output, flipped on Y",
false, false, {64, 64}, {}, false, true}, false, false, false, 0, {64, 64}, {}, false, true},
{"texture output, with offset", {"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 #ifndef MAGNUM_TARGET_GLES
{"texture output with implicit size", {"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 #endif
{"framebuffer output", {"framebuffer output",
true, false, {64, 64}, {}, false, false}, true, false, false, 0, {64, 64}, {}, false, false},
{"framebuffer output, flipped on X", {"framebuffer output, flipped on X",
true, false, {64, 64}, {}, true, false}, true, false, false, 0, {64, 64}, {}, true, false},
{"framebuffer output, flipped on Y", {"framebuffer output, flipped on Y",
true, false, {64, 64}, {}, false, true}, true, false, false, 0, {64, 64}, {}, false, true},
{"framebuffer output, with offset", {"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 #ifndef MAGNUM_TARGET_GLES
{"framebuffer output with implicit size", {"framebuffer output with implicit size",
true, true, {64, 64}, {}, false, false}, true, true, false, 0, {64, 64}, {}, false, false},
#endif #endif
}; };
@ -262,16 +276,34 @@ void DistanceFieldGLTest::run() {
#endif #endif
const GL::PixelType outputPixelType = GL::PixelType::UnsignedByte; const GL::PixelType outputPixelType = GL::PixelType::UnsignedByte;
GL::Texture2D outputTexture; GL::Texture2D outputTexture{NoCreate};
outputTexture.setMinificationFilter(GL::SamplerFilter::Nearest, GL::SamplerMipmap::Base) #ifndef MAGNUM_TARGET_GLES2
.setMagnificationFilter(GL::SamplerFilter::Nearest) GL::Texture2DArray outputTextureArray{NoCreate};
.setStorage(1, outputTextureFormat, data.size); if(data.array) {
outputTextureArray = GL::Texture2DArray{};
/* Fill the texture with some data to verify they don't affect the output outputTextureArray.setMinificationFilter(GL::SamplerFilter::Nearest, GL::SamplerMipmap::Base)
and aren't accidentally overwritten when running on just a .setMagnificationFilter(GL::SamplerFilter::Nearest)
subrectangle */ .setStorage(1, outputTextureFormat, {data.size, data.layer + 1});
outputTexture.setSubImage(0, {}, ImageView2D{outputPixelFormat, outputPixelType, data.size,
Containers::Array<char>{DirectInit, std::size_t(data.size.product()*GL::pixelFormatSize(outputPixelFormat, outputPixelType)), '\x66'}}); /* 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<char>{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<char>{DirectInit, std::size_t(data.size.product()*GL::pixelFormatSize(outputPixelFormat, outputPixelType)), '\x66'}});
}
GL::Framebuffer outputFramebuffer{NoCreate}; GL::Framebuffer outputFramebuffer{NoCreate};
if(data.framebuffer) { if(data.framebuffer) {
@ -296,7 +328,21 @@ void DistanceFieldGLTest::run() {
distanceField(input, outputFramebuffer, distanceField(input, outputFramebuffer,
Range2Di::fromSize(data.offset, Vector2i{64}), Range2Di::fromSize(data.offset, Vector2i{64}),
inputImage->size()); 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 #ifndef MAGNUM_TARGET_GLES
if(data.implicitOutputSize) if(data.implicitOutputSize)
distanceField(input, outputTexture, distanceField(input, outputTexture,
@ -327,14 +373,24 @@ void DistanceFieldGLTest::run() {
/* Verify that the other data weren't overwritten if processing just a /* Verify that the other data weren't overwritten if processing just a
subrange -- it should still have the original data kept */ subrange -- it should still have the original data kept */
if(data.offset.product()) { 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(); MAGNUM_VERIFY_NO_GL_ERROR();
CORRADE_COMPARE(actualOutputImage->data()[0], '\x66'); 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(); MAGNUM_VERIFY_NO_GL_ERROR();

Loading…
Cancel
Save