diff --git a/doc/changelog.dox b/doc/changelog.dox index 3af4adb4a..149f0a82b 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -356,6 +356,9 @@ See also: a proper documented default value instead of being left uninitialized. - @ref Math::sclerp() was not properly interpolating the translation if rotation was the same on both sides +- Improved @ref TextureTools::distanceField() to work better on shader + compilers that have problems compiling nested loops (WebGL implementations, + some ES2 devices) @subsection changelog-latest-docs Documentation diff --git a/src/Magnum/TextureTools/DistanceField.cpp b/src/Magnum/TextureTools/DistanceField.cpp index 0736db4b3..9b637b0f0 100644 --- a/src/Magnum/TextureTools/DistanceField.cpp +++ b/src/Magnum/TextureTools/DistanceField.cpp @@ -25,6 +25,7 @@ #include "DistanceField.h" +#include #include #include "Magnum/Math/Range.h" @@ -52,12 +53,7 @@ class DistanceFieldShader: public GL::AbstractShaderProgram { public: typedef GL::Attribute<0, Vector2> Position; - explicit DistanceFieldShader(); - - DistanceFieldShader& setRadius(Int radius) { - setUniform(radiusUniform, radius); - return *this; - } + explicit DistanceFieldShader(Int radius); DistanceFieldShader& setScaling(const Vector2& scaling) { setUniform(scalingUniform, scaling); @@ -79,12 +75,11 @@ class DistanceFieldShader: public GL::AbstractShaderProgram { units, so be careful to not step over that. ES3 on the same has 16. */ enum: Int { TextureUnit = 7 }; - Int radiusUniform{0}, - scalingUniform{1}, + Int scalingUniform{0}, imageSizeInvertedUniform; }; -DistanceFieldShader::DistanceFieldShader() { +DistanceFieldShader::DistanceFieldShader(Int radius) { #ifdef MAGNUM_BUILD_STATIC /* Import resources on static build, if not already */ if(!Utility::Resource::hasGroup("MagnumTextureTools")) @@ -103,7 +98,8 @@ DistanceFieldShader::DistanceFieldShader() { vert.addSource(rs.get("FullScreenTriangle.glsl")) .addSource(rs.get("DistanceFieldShader.vert")); - frag.addSource(rs.get("DistanceFieldShader.frag")); + frag.addSource(Utility::formatString("#define RADIUS {}\n", radius)) + .addSource(rs.get("DistanceFieldShader.frag")); CORRADE_INTERNAL_ASSERT_OUTPUT(GL::Shader::compile({vert, frag})); @@ -125,7 +121,6 @@ DistanceFieldShader::DistanceFieldShader() { if(!GL::Context::current().isExtensionSupported()) #endif { - radiusUniform = uniformLocation("radius"); scalingUniform = uniformLocation("scaling"); #ifndef MAGNUM_TARGET_GLES @@ -175,9 +170,8 @@ void distanceField(GL::Texture2D& input, GL::Texture2D& output, const Range2Di& return; } - DistanceFieldShader shader; - shader.setRadius(radius) - .setScaling(Vector2(imageSize)/Vector2(rectangle.size())) + DistanceFieldShader shader{radius}; + shader.setScaling(Vector2(imageSize)/Vector2(rectangle.size())) .bindTexture(input); #ifndef MAGNUM_TARGET_GLES diff --git a/src/Magnum/TextureTools/DistanceFieldShader.frag b/src/Magnum/TextureTools/DistanceFieldShader.frag index 2a4828000..e75ab7da4 100644 --- a/src/Magnum/TextureTools/DistanceFieldShader.frag +++ b/src/Magnum/TextureTools/DistanceFieldShader.frag @@ -40,11 +40,6 @@ #ifdef EXPLICIT_UNIFORM_LOCATION layout(location = 0) #endif -uniform lowp int radius; - -#ifdef EXPLICIT_UNIFORM_LOCATION -layout(location = 1) -#endif uniform mediump vec2 scaling; #ifdef EXPLICIT_TEXTURE_LAYER @@ -58,7 +53,7 @@ layout(pixel_center_integer) in mediump vec4 gl_FragCoord; #endif #else #ifdef EXPLICIT_UNIFORM_LOCATION -layout(location = 2) +layout(location = 1) #endif uniform mediump vec2 imageSizeInverted; #endif @@ -108,12 +103,13 @@ void main() { const highp float sign = isInside ? 1.0 : -1.0; /* Minimal found distance is just out of the radius (i.e. infinity) */ - highp float minDistanceSquared = float((radius+1)*(radius+1)); + highp float minDistanceSquared = float((RADIUS+1)*(RADIUS+1)); /* Go in circles around the point and find nearest value */ - int radiusLimit = radius; - for(int i = 1; i <= radiusLimit; ++i) { - for(int j = 0, jmax = i*2; j < jmax; ++j) { + int radiusLimit = RADIUS; + for(int i = 1; i <= RADIUS; ++i) { + int jmax = i*2; + for(int j = 0; j < RADIUS*2; ++j) { #ifdef TEXELFETCH_USABLE const lowp ivec2 offset = ivec2(-i+j, i); #else @@ -142,14 +138,18 @@ void main() { value, e.g. for distance 3.5 we can find smaller value even in radius 3 */ #ifdef NEW_GLSL - radiusLimit = min(radius, int(floor(length(vec2(offset))))); + radiusLimit = min(RADIUS, int(floor(length(vec2(offset))))); #else - radiusLimit = int(min(float(radius), floor(length(vec2(offset))))); + radiusLimit = int(min(float(RADIUS), floor(length(vec2(offset))))); #endif } + + if(j + 1 >= jmax) break; } + + if(i + 1 > radiusLimit) break; } /* Final signed distance, normalized from [-radius-1, radius+1] to [0, 1] */ - value = sign*sqrt(minDistanceSquared)/float(radius*2+2)+0.5; + value = sign*sqrt(minDistanceSquared)/float(RADIUS*2+2)+0.5; } diff --git a/src/Magnum/TextureTools/Test/DistanceFieldGLTestFiles/output.tga b/src/Magnum/TextureTools/Test/DistanceFieldGLTestFiles/output.tga index 278ec6a32..f6982a590 100644 Binary files a/src/Magnum/TextureTools/Test/DistanceFieldGLTestFiles/output.tga and b/src/Magnum/TextureTools/Test/DistanceFieldGLTestFiles/output.tga differ