Skip to content

Commit

Permalink
Shaders: first DistanceFieldVectorShader implementation.
Browse files Browse the repository at this point in the history
Currently only fill and outline can be specified. Also crosslinked from
documentation of VectorShader and TextureTools::distanceField().
  • Loading branch information
mosra committed Mar 3, 2013
1 parent 549558b commit 2d98dad
Show file tree
Hide file tree
Showing 7 changed files with 263 additions and 2 deletions.
4 changes: 3 additions & 1 deletion src/Shaders/CMakeLists.txt
Expand Up @@ -2,16 +2,18 @@ corrade_add_resource(MagnumShaders_RCS MagnumShaders
AbstractVectorShader2D.vert AbstractVectorShader3D.vert
FlatShader2D.vert FlatShader3D.vert FlatShader.frag
PhongShader.vert PhongShader.frag
VectorShader.frag
VectorShader.frag DistanceFieldVectorShader.frag
VertexColorShader2D.vert VertexColorShader3D.vert VertexColorShader.frag
compatibility.glsl)
set(MagnumShaders_SRCS
DistanceFieldVectorShader.cpp
FlatShader.cpp
PhongShader.cpp
VectorShader.cpp
VertexColorShader.cpp
${MagnumShaders_RCS})
set(MagnumShaders_HEADERS
DistanceFieldVectorShader.h
AbstractVectorShader.h
FlatShader.h
PhongShader.h
Expand Down
85 changes: 85 additions & 0 deletions src/Shaders/DistanceFieldVectorShader.cpp
@@ -0,0 +1,85 @@
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
This file is part of Magnum.
Magnum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3
only, as published by the Free Software Foundation.
Magnum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License version 3 for more details.
*/

#include "DistanceFieldVectorShader.h"

#include <Utility/Resource.h>

#include "Context.h"
#include "Extensions.h"
#include "Shader.h"

namespace Magnum { namespace Shaders {

namespace {
template<UnsignedInt> constexpr const char* vertexShaderName();
template<> constexpr const char* vertexShaderName<2>() { return "AbstractVectorShader2D.vert"; }
template<> constexpr const char* vertexShaderName<3>() { return "AbstractVectorShader3D.vert"; }
}

template<UnsignedInt dimensions> DistanceFieldVectorShader<dimensions>::DistanceFieldVectorShader(): transformationProjectionMatrixUniform(0), colorUniform(1), outlineColorUniform(2), outlineRangeUniform(3), smoothnessUniform(4) {
Corrade::Utility::Resource rs("MagnumShaders");

#ifndef MAGNUM_TARGET_GLES
Version v = Context::current()->supportedVersion({Version::GL320, Version::GL210});
#else
Version v = Context::current()->supportedVersion({Version::GLES300, Version::GLES200});
#endif

Shader vertexShader(v, Shader::Type::Vertex);
vertexShader.addSource(rs.get("compatibility.glsl"));
vertexShader.addSource(rs.get(vertexShaderName<dimensions>()));
AbstractShaderProgram::attachShader(vertexShader);

Shader fragmentShader(v, Shader::Type::Fragment);
fragmentShader.addSource(rs.get("compatibility.glsl"));
fragmentShader.addSource(rs.get("DistanceFieldVectorShader.frag"));
AbstractShaderProgram::attachShader(fragmentShader);

#ifndef MAGNUM_TARGET_GLES
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::explicit_attrib_location>() ||
Context::current()->version() == Version::GL210) {
#else
if(!Context::current()->isVersionSupported(Version::GLES300)) {
#endif
AbstractShaderProgram::bindAttributeLocation(AbstractVectorShader<dimensions>::Position::Location, "position");
AbstractShaderProgram::bindAttributeLocation(AbstractVectorShader<dimensions>::TextureCoordinates::Location, "textureCoordinates");
}

AbstractShaderProgram::link();

#ifndef MAGNUM_TARGET_GLES
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::explicit_uniform_location>()) {
#else
{
#endif
transformationProjectionMatrixUniform = AbstractShaderProgram::uniformLocation("transformationProjectionMatrix");
colorUniform = AbstractShaderProgram::uniformLocation("color");
outlineColorUniform = AbstractShaderProgram::uniformLocation("outlineColor");
outlineRangeUniform = AbstractShaderProgram::uniformLocation("outlineRange");
smoothnessUniform = AbstractShaderProgram::uniformLocation("smoothness");
}

#ifndef MAGNUM_TARGET_GLES
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::shading_language_420pack>())
AbstractShaderProgram::setUniform(AbstractShaderProgram::uniformLocation("vectorTexture"),
AbstractVectorShader<dimensions>::VectorTextureLayer);
#endif
}

template class DistanceFieldVectorShader<2>;
template class DistanceFieldVectorShader<3>;

}}
49 changes: 49 additions & 0 deletions src/Shaders/DistanceFieldVectorShader.frag
@@ -0,0 +1,49 @@
#ifndef NEW_GLSL
#define in varying
#define fragmentColor gl_FragColor
#endif

#ifndef GL_ES
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 1) uniform lowp vec4 color;
layout(location = 2) uniform lowp vec4 outlineColor;
layout(location = 3) uniform lowp vec2 outlineRange = vec2(0.5, 0.0);
layout(location = 4) uniform lowp float smoothness = 0.04;
#else
uniform lowp vec4 color;
uniform lowp vec4 outlineColor;
uniform lowp vec2 outlineRange = vec2(0.5, 0.0);
uniform lowp float smoothness = 0.04;
#endif
#else
uniform lowp vec4 color;
uniform lowp vec4 outlineColor;
uniform lowp vec2 outlineRange;
uniform lowp float smoothness;
#endif

#ifdef EXPLICIT_TEXTURE_LAYER
layout(binding = 16) uniform sampler2D vectorTexture;
#else
uniform lowp sampler2D vectorTexture;
#endif

in vec2 fragmentTextureCoordinates;

#ifdef NEW_GLSL
out vec4 fragmentColor;
#endif

void main() {
lowp float intensity = texture(vectorTexture, fragmentTextureCoordinates).r;

/* Fill color */
fragmentColor = smoothstep(outlineRange.x-smoothness, outlineRange.x+smoothness, intensity)*color;

/* Outline */
if(outlineRange.x < outlineRange.y) {
lowp float mid = (outlineRange.x + outlineRange.y)/2.0;
lowp float half = (outlineRange.y - outlineRange.x)/2.0;
fragmentColor += smoothstep(half+smoothness, half-smoothness, distance(mid, intensity))*outlineColor;
}
}
118 changes: 118 additions & 0 deletions src/Shaders/DistanceFieldVectorShader.h
@@ -0,0 +1,118 @@
#ifndef Magnum_Shaders_DistanceFieldVectorShader_h
#define Magnum_Shaders_DistanceFieldVectorShader_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
This file is part of Magnum.
Magnum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3
only, as published by the Free Software Foundation.
Magnum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License version 3 for more details.
*/

/** @file
* @brief Class Magnum::Shaders::DistanceFieldVectorShader, typedef Magnum::Shaders::DistanceFieldVectorShader2D, Magnum::Shaders::DistanceFieldVectorShader3D
*/

#include "Math/Matrix3.h"
#include "Math/Matrix4.h"
#include "AbstractVectorShader.h"

#include "magnumShadersVisibility.h"

namespace Magnum { namespace Shaders {

/**
@brief Distance field vector shader
Renders vector art in form of signed distance field. See TextureTools::distanceField()
for more information. Note that the final rendered outlook will greatly depend
on radius of input distance field and value passed to setSmoothness().
@see DistanceFieldVectorShader2D, DistanceFieldVectorShader3D
*/
template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVectorShader: public AbstractVectorShader<dimensions> {
public:
DistanceFieldVectorShader();

/** @brief Set transformation and projection matrix */
inline DistanceFieldVectorShader* setTransformationProjectionMatrix(const typename DimensionTraits<dimensions>::MatrixType& matrix) {
AbstractShaderProgram::setUniform(transformationProjectionMatrixUniform, matrix);
return this;
}

/**
* @brief Set fill color
* @return Pointer to self (for method chaining)
*
* @see setOutlineColor()
*/
inline DistanceFieldVectorShader* setColor(const Color4<>& color) {
AbstractShaderProgram::setUniform(colorUniform, color);
return this;
}

/**
* @brief Set outline color
* @return Pointer to self (for method chaining)
*
* @see setOutlineRange(), setColor()
*/
inline DistanceFieldVectorShader* setOutlineColor(const Color4<>& color) {
AbstractShaderProgram::setUniform(outlineColorUniform, color);
return this;
}

/**
* @brief Set outline range
* @return Pointer to self (for method chaining)
*
* Parameter @p start describes where fill ends and possible outline
* starts. Initial value is `0.5f`, smaller values will make the vector
* art look thinner, larger will make it look thicker.
*
* Parameter @p end describes where outline ends. If set to value
* smaller than @p start the outline is not drawn. Initial value is
* `0.0f`.
*
* @see setOutlineColor()
*/
inline DistanceFieldVectorShader* setOutlineRange(Float start, Float end) {
AbstractShaderProgram::setUniform(outlineRangeUniform, Vector2(start, end));
return this;
}

/**
* @brief Set smoothness radius
* @return Pointer to self (for method chaining)
*
* Larger values will make edges look less aliased (but blurry), smaller
* values will make them look more crisp (but possibly aliased). Initial
* value is `0.04f`.
*/
inline DistanceFieldVectorShader* setSmoothness(Float value) {
AbstractShaderProgram::setUniform(smoothnessUniform, value);
return this;
}

private:
Int transformationProjectionMatrixUniform,
colorUniform,
outlineColorUniform,
outlineRangeUniform,
smoothnessUniform;
};

/** @brief Two-dimensional distance field vector shader */
typedef DistanceFieldVectorShader<2> DistanceFieldVectorShader2D;

/** @brief Three-dimensional distance field vector shader */
typedef DistanceFieldVectorShader<3> DistanceFieldVectorShader3D;

}}

#endif
5 changes: 5 additions & 0 deletions src/Shaders/Shaders.h
Expand Up @@ -25,6 +25,11 @@ namespace Magnum { namespace Shaders {

/** @todoc remove when doxygen is sane again */
#ifndef DOXYGEN_GENERATING_OUTPUT

template<UnsignedInt> class DistanceFieldVectorShader;
typedef DistanceFieldVectorShader<2> DistanceFieldVectorShader2D;
typedef DistanceFieldVectorShader<3> DistanceFieldVectorShader3D;

template<UnsignedInt> class AbstractVectorShader;
typedef AbstractVectorShader<2> AbstractVectorShader2D;
typedef AbstractVectorShader<3> AbstractVectorShader3D;
Expand Down
2 changes: 2 additions & 0 deletions src/Shaders/VectorShader.h
Expand Up @@ -30,6 +30,8 @@ namespace Magnum { namespace Shaders {
/**
@brief Vector shader
Renders vector art in plain grayscale form. See also DistanceFieldVectorShader
for more advanced effects.
@see VectorShader2D, VectorShader3D
*/
template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorShader: public AbstractVectorShader<dimensions> {
Expand Down
2 changes: 1 addition & 1 deletion src/TextureTools/DistanceField.h
Expand Up @@ -50,7 +50,7 @@ the pixel was originally black and nearest white pixel is farther than
The resulting texture can be used with bilinear filtering. It can be converted
back to binary form in shader using e.g. GLSL `smoothstep()` function with step
around `0.5` to create antialiased edges. Or you can exploit the distance field
features to create many other effects.
features to create many other effects. See also Shaders::DistanceFieldVectorShader.
Based on: *Chris Green - Improved Alpha-Tested Magnification for Vector Textures
and Special Effects, SIGGRAPH 2007,
Expand Down

0 comments on commit 2d98dad

Please sign in to comment.