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. 86
      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;
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

15
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
}}

34
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> _state;

86
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;
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<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
/* 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};
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,6 +373,11 @@ 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()) {
#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();
@ -334,6 +385,11 @@ void DistanceFieldGLTest::run() {
CORRADE_COMPARE(actualOutputImage->data()[0], '\x66');
}
#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();

Loading…
Cancel
Save