diff --git a/src/Shaders/CMakeLists.txt b/src/Shaders/CMakeLists.txt index f20f432c6..41c0e0731 100644 --- a/src/Shaders/CMakeLists.txt +++ b/src/Shaders/CMakeLists.txt @@ -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 diff --git a/src/Shaders/DistanceFieldVectorShader.cpp b/src/Shaders/DistanceFieldVectorShader.cpp new file mode 100644 index 000000000..6631a0ddf --- /dev/null +++ b/src/Shaders/DistanceFieldVectorShader.cpp @@ -0,0 +1,85 @@ +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + 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 + +#include "Context.h" +#include "Extensions.h" +#include "Shader.h" + +namespace Magnum { namespace Shaders { + +namespace { + template constexpr const char* vertexShaderName(); + template<> constexpr const char* vertexShaderName<2>() { return "AbstractVectorShader2D.vert"; } + template<> constexpr const char* vertexShaderName<3>() { return "AbstractVectorShader3D.vert"; } +} + +template DistanceFieldVectorShader::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())); + 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() || + Context::current()->version() == Version::GL210) { + #else + if(!Context::current()->isVersionSupported(Version::GLES300)) { + #endif + AbstractShaderProgram::bindAttributeLocation(AbstractVectorShader::Position::Location, "position"); + AbstractShaderProgram::bindAttributeLocation(AbstractVectorShader::TextureCoordinates::Location, "textureCoordinates"); + } + + AbstractShaderProgram::link(); + + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) { + #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()) + AbstractShaderProgram::setUniform(AbstractShaderProgram::uniformLocation("vectorTexture"), + AbstractVectorShader::VectorTextureLayer); + #endif +} + +template class DistanceFieldVectorShader<2>; +template class DistanceFieldVectorShader<3>; + +}} diff --git a/src/Shaders/DistanceFieldVectorShader.frag b/src/Shaders/DistanceFieldVectorShader.frag new file mode 100644 index 000000000..7ec900bf1 --- /dev/null +++ b/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; + } +} diff --git a/src/Shaders/DistanceFieldVectorShader.h b/src/Shaders/DistanceFieldVectorShader.h new file mode 100644 index 000000000..40f58ab49 --- /dev/null +++ b/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š + + 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 class MAGNUM_SHADERS_EXPORT DistanceFieldVectorShader: public AbstractVectorShader { + public: + DistanceFieldVectorShader(); + + /** @brief Set transformation and projection matrix */ + inline DistanceFieldVectorShader* setTransformationProjectionMatrix(const typename DimensionTraits::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 diff --git a/src/Shaders/Shaders.h b/src/Shaders/Shaders.h index d068b588e..f5e8f2a40 100644 --- a/src/Shaders/Shaders.h +++ b/src/Shaders/Shaders.h @@ -25,6 +25,11 @@ namespace Magnum { namespace Shaders { /** @todoc remove when doxygen is sane again */ #ifndef DOXYGEN_GENERATING_OUTPUT + +template class DistanceFieldVectorShader; +typedef DistanceFieldVectorShader<2> DistanceFieldVectorShader2D; +typedef DistanceFieldVectorShader<3> DistanceFieldVectorShader3D; + template class AbstractVectorShader; typedef AbstractVectorShader<2> AbstractVectorShader2D; typedef AbstractVectorShader<3> AbstractVectorShader3D; diff --git a/src/Shaders/VectorShader.h b/src/Shaders/VectorShader.h index ccd177352..f2dee2480 100644 --- a/src/Shaders/VectorShader.h +++ b/src/Shaders/VectorShader.h @@ -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 class MAGNUM_SHADERS_EXPORT VectorShader: public AbstractVectorShader { diff --git a/src/TextureTools/DistanceField.h b/src/TextureTools/DistanceField.h index fe107020d..85bd4ab6d 100644 --- a/src/TextureTools/DistanceField.h +++ b/src/TextureTools/DistanceField.h @@ -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,