Browse Source

TextureTools: add a DistanceField overload taking a framebuffer.

So one can directly read it back on GLES without having to wrap the
texture in a framebuffer again.

This change also puts the framebuffer completeness check *before* the
clear() and bind() which makes it no longer emit a GL error. The error
is still silent though, which isn't nice. Gotta fix that eventually as
well.
pull/617/head
Vladimír Vondruš 3 years ago
parent
commit
5f55f9e756
  1. 3
      doc/changelog.dox
  2. 30
      src/Magnum/TextureTools/DistanceField.cpp
  3. 21
      src/Magnum/TextureTools/DistanceField.h
  4. 22
      src/Magnum/TextureTools/Test/DistanceFieldGLTest.cpp

3
doc/changelog.dox

@ -329,6 +329,9 @@ See also:
- New @ref TextureTools::atlasArrayPowerOfTwo() utility for optimal packing - New @ref TextureTools::atlasArrayPowerOfTwo() utility for optimal packing
of power-of-two textures into a texture atlas array of power-of-two textures into a texture atlas array
- Added a @ref TextureTools::DistanceField::operator()() overload taking a
@ref GL::Framebuffer instead of a @ref GL::Texture as an output for an
easier ability to download the resulting image on OpenGL ES platforms
@subsubsection changelog-latest-new-trade Trade library @subsubsection changelog-latest-new-trade Trade library

30
src/Magnum/TextureTools/DistanceField.cpp

@ -189,7 +189,7 @@ DistanceField::~DistanceField() = default;
UnsignedInt DistanceField::radius() const { return _state->radius; } UnsignedInt DistanceField::radius() const { return _state->radius; }
void DistanceField::operator()(GL::Texture2D& input, GL::Texture2D& output, const Range2Di& rectangle, const Vector2i& void DistanceField::operator()(GL::Texture2D& input, GL::Framebuffer& output, const Range2Di& rectangle, const Vector2i&
#ifdef MAGNUM_TARGET_GLES #ifdef MAGNUM_TARGET_GLES
imageSize imageSize
#endif #endif
@ -200,20 +200,17 @@ void DistanceField::operator()(GL::Texture2D& input, GL::Texture2D& output, cons
Vector2i imageSize = input.imageSize(0); Vector2i imageSize = input.imageSize(0);
#endif #endif
/* Framebuffer is instantiated here so it gets correctly unbound at the end const GL::Framebuffer::Status status = output.checkStatus(GL::FramebufferTarget::Draw);
(and bound framebuffer reset back to the default) */
GL::Framebuffer framebuffer{rectangle};
framebuffer.attachTexture(GL::Framebuffer::ColorAttachment(0), output, 0)
.clear(GL::FramebufferClear::Color)
.bind();
const GL::Framebuffer::Status status = framebuffer.checkStatus(GL::FramebufferTarget::Draw);
if(status != GL::Framebuffer::Status::Complete) { if(status != GL::Framebuffer::Status::Complete) {
Error() << "TextureTools::DistanceField: cannot render to given output texture, unexpected framebuffer status" Error() << "TextureTools::DistanceField: cannot render to given output texture, unexpected framebuffer status"
<< status; << status;
return; return;
} }
output
.clear(GL::FramebufferClear::Color)
.bind();
_state->shader.setScaling(Vector2(imageSize)/Vector2(rectangle.size())) _state->shader.setScaling(Vector2(imageSize)/Vector2(rectangle.size()))
.bindTexture(input); .bindTexture(input);
@ -230,4 +227,19 @@ void DistanceField::operator()(GL::Texture2D& input, GL::Texture2D& output, cons
_state->shader.draw(_state->mesh); _state->shader.draw(_state->mesh);
} }
void DistanceField::operator()(GL::Texture2D& input, GL::Texture2D& output, const Range2Di& rectangle, const Vector2i&
#ifdef MAGNUM_TARGET_GLES
imageSize
#endif
) {
GL::Framebuffer framebuffer{rectangle};
framebuffer.attachTexture(GL::Framebuffer::ColorAttachment(0), output, 0);
operator()(input, framebuffer, rectangle
#ifdef MAGNUM_TARGET_GLES
, imageSize
#endif
);
}
}} }}

21
src/Magnum/TextureTools/DistanceField.h

@ -110,13 +110,32 @@ class MAGNUM_TEXTURETOOLS_EXPORT DistanceField {
UnsignedInt radius() const; UnsignedInt radius() const;
/** /**
* @brief Calculate the distance field * @brief Calculate the distance field to a framebuffer
* @param input Input texture
* @param output Output framebuffer
* @param rectangle Rectangle in output texture where to render
* @param imageSize Input texture size. Needed only for OpenGL ES,
* on desktop GL the information is gathered automatically using
* @ref GL::Texture2D::imageSize().
* @m_since_latest
*/
void operator()(GL::Texture2D& input, GL::Framebuffer& output, const Range2Di& rectangle, const Vector2i& imageSize
#ifndef MAGNUM_TARGET_GLES
= {}
#endif
);
/**
* @brief Calculate the distance field to a texture
* @param input Input texture * @param input Input texture
* @param output Output texture * @param output Output texture
* @param rectangle Rectangle in output texture where to render * @param rectangle Rectangle in output texture where to render
* @param imageSize Input texture size. Needed only for OpenGL ES, * @param imageSize Input texture size. Needed only for OpenGL ES,
* on desktop GL the information is gathered automatically using * on desktop GL the information is gathered automatically using
* @ref GL::Texture2D::imageSize(). * @ref GL::Texture2D::imageSize().
*
* Creates a framebuffer with @p output attached and calls
* @ref operator()(GL::Texture2D&, GL::Framebuffer&, const Range2Di&, const Vector2i&).
*/ */
void operator()(GL::Texture2D& input, GL::Texture2D& output, const Range2Di& rectangle, const Vector2i& imageSize void operator()(GL::Texture2D& input, GL::Texture2D& output, const Range2Di& rectangle, const Vector2i& imageSize
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES

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

@ -23,9 +23,11 @@
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <sstream>
#include <Corrade/Containers/String.h> #include <Corrade/Containers/String.h>
#include <Corrade/PluginManager/AbstractManager.h> #include <Corrade/PluginManager/AbstractManager.h>
#include <Corrade/Utility/Path.h> #include <Corrade/Utility/Path.h>
#include <Corrade/Utility/DebugStl.h>
#ifdef CORRADE_TARGET_APPLE #ifdef CORRADE_TARGET_APPLE
#include <Corrade/Containers/Pair.h> #include <Corrade/Containers/Pair.h>
@ -64,6 +66,8 @@ namespace Magnum { namespace TextureTools { namespace Test { namespace {
struct DistanceFieldGLTest: GL::OpenGLTester { struct DistanceFieldGLTest: GL::OpenGLTester {
explicit DistanceFieldGLTest(); explicit DistanceFieldGLTest();
/* This tests the GL::Texture overload, which itself calls into the
GL::Framebuffer overload so both are covered */
void test(); void test();
#ifndef MAGNUM_TARGET_WEBGL #ifndef MAGNUM_TARGET_WEBGL
void benchmark(); void benchmark();
@ -170,24 +174,28 @@ void DistanceFieldGLTest::test() {
MAGNUM_VERIFY_NO_GL_ERROR(); MAGNUM_VERIFY_NO_GL_ERROR();
std::ostringstream out;
{
Error redirectError{&out};
distanceField(input, output, {{}, Vector2i{64}} distanceField(input, output, {{}, Vector2i{64}}
#ifdef MAGNUM_TARGET_GLES #ifdef MAGNUM_TARGET_GLES
, inputImage->size() , inputImage->size()
#endif #endif
); );
}
#ifdef MAGNUM_TARGET_GLES #ifdef MAGNUM_TARGET_GLES
{
/* Probably due to the luminance target pixel format? Works with 4.1, /* Probably due to the luminance target pixel format? Works with 4.1,
didn't find any commit in between that would clearly affect didn't find any commit in between that would clearly affect
this. */ this. */
CORRADE_EXPECT_FAIL_IF(GL::Context::current().versionString().contains("SwiftShader 4.0.0"_s), if(GL::Context::current().versionString().contains("SwiftShader 4.0.0"_s)) {
"SwiftShader 4.0.0 has a bug where the framebuffer is considered incomplete."); CORRADE_COMPARE(out.str(), "TextureTools::DistanceField: cannot render to given output texture, unexpected framebuffer status GL::Framebuffer::Status::IncompleteAttachment\n");
MAGNUM_VERIFY_NO_GL_ERROR(); CORRADE_SKIP("SwiftShader 4.0.0 has a bug where the framebuffer is considered incomplete.");
if(GL::Context::current().versionString().contains("SwiftShader 4.0.0"_s)) } else
CORRADE_SKIP("Skipping the rest of the test.");
}
#endif #endif
{
CORRADE_COMPARE(out.str(), "");
}
Containers::Optional<Image2D> actualOutputImage; Containers::Optional<Image2D> actualOutputImage;
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2

Loading…
Cancel
Save