diff --git a/CMakeModules/BuildSteps/CreateShaderCpp.cmake b/CMakeModules/BuildSteps/CreateShaderCpp.cmake new file mode 100644 index 0000000000..6c7c0dc14a --- /dev/null +++ b/CMakeModules/BuildSteps/CreateShaderCpp.cmake @@ -0,0 +1,35 @@ +file( READ ${SOURCE} SOURCE_TEXT ) + +set( outCppText +" +#include <${OUTHEADERFILE}> + +namespace KIGFX { +namespace BUILTIN_SHADERS { +const char ${OUTVARNAME}[] = R\"SHADER_SOURCE( +${SOURCE_TEXT} +)SHADER_SOURCE\"; +} +} +" ) + +file( + WRITE ${DESTINATION_SOURCE_DIR}/${OUTCPPFILE} + "${outCppText}" +) + + +set( outHeaderText +"namespace KIGFX { + namespace BUILTIN_SHADERS { + extern const char ${OUTVARNAME}[]; + } +}" +) + +file( + WRITE ${DESTINATION_HEADER_DIR}/${OUTHEADERFILE} + "${outHeaderText}" +) + +message(STATUS "Shader ${SOURCE} converted to ${DESTINATION_SOURCE_DIR}/${OUTCPPFILE}") \ No newline at end of file diff --git a/common/gal/CMakeLists.txt b/common/gal/CMakeLists.txt index c5a66333bb..73c8b21551 100644 --- a/common/gal/CMakeLists.txt +++ b/common/gal/CMakeLists.txt @@ -1,7 +1,7 @@ set( GAL_SRCS # Common part - ../callback_gal.cpp + ../callback_gal.cpp ../draw_panel_gal.cpp ../gl_context_mgr.cpp ../newstroke_font.cpp @@ -52,9 +52,33 @@ target_link_libraries( gal ${PIXMAN_LIBRARIES} ${OPENGL_LIBRARIES} ${GDI_PLUS_LIBRARIES} - # outline font support - ${FREETYPE_LIBRARIES} - ${HarfBuzz_LIBRARIES} - ${Fontconfig_LIBRARIES} + # outline font support + ${FREETYPE_LIBRARIES} + ${HarfBuzz_LIBRARIES} + ${Fontconfig_LIBRARIES} ) +function( add_shader outTarget inFile shaderName ) + set(outCppName "${shaderName}.cpp") + set(outHeaderName "${shaderName}.h") + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${outCppName} + ${CMAKE_BINARY_DIR}/include/gal/shaders/${outHeaderName} + COMMAND ${CMAKE_COMMAND} + -DSOURCE="${CMAKE_CURRENT_SOURCE_DIR}/shaders/${inFile}" + -DDESTINATION_SOURCE_DIR="${CMAKE_CURRENT_BINARY_DIR}/" + -DDESTINATION_HEADER_DIR="${CMAKE_BINARY_DIR}/include/gal/shaders/" + -DOUTCPPFILE="${outCppName}" + -DOUTHEADERFILE="${outHeaderName}" + -DOUTVARNAME="${shaderName}_shader" + -P ${CMAKE_MODULE_PATH}/BuildSteps/CreateShaderCpp.cmake + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/shaders/${inFile} + ${CMAKE_MODULE_PATH}/BuildSteps/CreateShaderCpp.cmake + ) + + target_sources( ${outTarget} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/${outCppName} ) + target_include_directories( ${outTarget} PUBLIC ${CMAKE_BINARY_DIR}/include/gal/shaders/ ) +endfunction() + +add_shader( gal kicad_frag.glsl glsl_kicad_frag ) +add_shader( gal kicad_vert.glsl glsl_kicad_vert ) \ No newline at end of file diff --git a/common/gal/opengl/gl_builtin_shaders.cpp b/common/gal/opengl/gl_builtin_shaders.cpp index 2c75d0988e..94a99a2e32 100644 --- a/common/gal/opengl/gl_builtin_shaders.cpp +++ b/common/gal/opengl/gl_builtin_shaders.cpp @@ -26,392 +26,6 @@ namespace KIGFX { namespace BUILTIN_SHADERS { -/* - * - * KiCad shaders - * - */ - -const char kicad_vertex_shader[] = R"SHADER_SOURCE( - -/* - * This program source code file is part of KICAD, a free EDA CAD application. - * - * Copyright (C) 2013-2016 CERN - * @author Maciej Suminski - * - * Vertex shader - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you may find one here: - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * or you may search the http://www.gnu.org website for the version 2 license, - * or you may write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#version 120 - -// Shader types -const float SHADER_FILLED_CIRCLE = 2.0; -const float SHADER_STROKED_CIRCLE = 3.0; -const float SHADER_FONT = 4.0; -const float SHADER_LINE_A = 5.0; -const float SHADER_LINE_B = 6.0; -const float SHADER_LINE_C = 7.0; -const float SHADER_LINE_D = 8.0; -const float SHADER_LINE_E = 9.0; -const float SHADER_LINE_F = 10.0; - -// Minimum line width -const float MIN_WIDTH = 1.0; - -attribute vec4 attrShaderParams; -varying vec4 shaderParams; -varying vec2 circleCoords; -uniform float worldPixelSize; -uniform vec2 screenPixelSize; -uniform float pixelSizeMultiplier; -uniform float minLinePixelWidth; -uniform vec2 antialiasingOffset; - - -float roundr( float f, float r ) -{ - return floor(f / r + 0.5) * r; -} - -vec4 roundv( vec4 x, vec2 t) -{ - return vec4( roundr(x.x, t.x), roundr(x.y, t.y), x.z, x.w ); -} - -void computeLineCoords( bool posture, vec2 vs, vec2 vp, vec2 texcoord, vec2 dir, float lineWidth, bool endV ) -{ - float lineLength = length(vs); - vec4 screenPos = gl_ModelViewProjectionMatrix * gl_Vertex + vec4(1, 1, 0, 0); - float w = ((lineWidth == 0.0) ? worldPixelSize : lineWidth ); - float pixelWidth = roundr( w / worldPixelSize, 1.0 ); - float aspect = ( lineLength + w ) / w; - vec4 color = gl_Color; - vec2 s = sign( vec2( gl_ModelViewProjectionMatrix[0][0], gl_ModelViewProjectionMatrix[1][1] ) ); - - - if( pixelWidth < 1.0 ) - pixelWidth = 1.0; - - if ( pixelWidth > 1.0 || pixelSizeMultiplier > 1.0 ) - { - vec2 offsetNorm = (vs + vp) * pixelWidth / lineLength * 0.5; - vec4 screenOffset = vec4( s.x * offsetNorm.x * screenPixelSize.x, s.y * offsetNorm.y * screenPixelSize.y , 0, 0); - vec4 adjust = vec4(-1, -1, 0, 0); - - if( mod( pixelWidth * pixelSizeMultiplier, 2.0 ) > 0.9 ) - { - adjust += vec4( screenPixelSize.x, screenPixelSize.y, 0, 0 ) * 0.5; - } - - gl_Position = roundv(screenPos, screenPixelSize) + adjust + screenOffset; - - shaderParams[0] = SHADER_LINE_A; - } - else { - vec4 pos0 = screenPos; - pos0.xy += ( posture ? dir.xy : dir.yx ) * screenPixelSize / 2.0; - - if(posture) - { - pos0.y -= screenPixelSize.y * sign(vs.y) * 0.5; - } - else - { - pos0.x += screenPixelSize.x * sign(vs.x) * 0.5; - } - - gl_Position = pos0 - vec4(1, 1, 0, 0); - shaderParams[0] = SHADER_LINE_B; - } - - shaderParams[1] = aspect; - - gl_TexCoord[0].st = vec2(aspect * texcoord.x, texcoord.y); - gl_FrontColor = gl_Color; -} - - -void computeCircleCoords( float mode, float vertexIndex, float radius, float lineWidth ) -{ - vec4 delta; - vec4 center = roundv( gl_ModelViewProjectionMatrix * gl_Vertex + vec4(1, 1, 0, 0), screenPixelSize ); - float pixelWidth = roundr( lineWidth / worldPixelSize, 1.0); - float pixelR = roundr( radius / worldPixelSize, 1.0); - - if( mode == SHADER_STROKED_CIRCLE) - pixelR += pixelWidth / 2.0; - - vec4 adjust = vec4(-1, -1, 0, 0); - - if( pixelWidth < 1.0 ) - pixelWidth = 1.0; - - if( vertexIndex == 1.0 ) - { - circleCoords = vec2( -sqrt( 3.0 ), -1.0 ); - delta = vec4( -pixelR * sqrt(3.0), -pixelR, 0, 0 ); - } - else if( vertexIndex == 2.0 ) - { - circleCoords = vec2( sqrt( 3.0 ), -1.0 ); - delta = vec4( pixelR * sqrt( 3.0 ), -pixelR, 0, 0 ); - } - else if( vertexIndex == 3.0 ) - { - circleCoords = vec2( 0.0, 2.0 ); - delta = vec4( 0, 2 * pixelR, 0, 0 ); - } - else if( vertexIndex == 4.0 ) - { - circleCoords = vec2( -sqrt( 3.0 ), 0.0 ); - delta = vec4( 0, 0, 0, 0 ); - } - else if( vertexIndex == 5.0 ) - { - circleCoords = vec2( sqrt( 3.0 ), 0.0 ); - delta = vec4( 0, 0, 0, 0 ); - } - else if( vertexIndex == 6.0 ) - { - circleCoords = vec2( 0.0, 2.0 ); - delta = vec4( 0, 0, 0, 0 ); - } - - shaderParams[2] = pixelR; - shaderParams[3] = pixelWidth; - - delta.x *= screenPixelSize.x; - delta.y *= screenPixelSize.y; - - gl_Position = center + delta + adjust; - gl_FrontColor = gl_Color; -} - - -void main() -{ - float mode = attrShaderParams[0]; - - // Pass attributes to the fragment shader - shaderParams = attrShaderParams; - - float lineWidth = shaderParams.y; - vec2 vs = shaderParams.zw; - vec2 vp = vec2(-vs.y, vs.x); - bool posture = abs( vs.x ) < abs(vs.y); - - if( mode == SHADER_LINE_A ) - computeLineCoords( posture, -vs, vp, vec2( -1, -1 ), vec2( -1, 0 ), lineWidth, false ); - else if( mode == SHADER_LINE_B ) - computeLineCoords( posture, -vs, -vp, vec2( -1, 1 ), vec2( 1, 0 ), lineWidth, false ); - else if( mode == SHADER_LINE_C ) - computeLineCoords( posture, vs, -vp, vec2( 1, 1 ), vec2( 1, 0 ), lineWidth, true ); - else if( mode == SHADER_LINE_D ) - computeLineCoords( posture, vs, -vp, vec2( -1, -1 ), vec2( 1, 0 ), lineWidth, true ); - else if( mode == SHADER_LINE_E ) - computeLineCoords( posture, vs, vp, vec2( -1, 1 ), vec2( -1, 0 ), lineWidth, true ); - else if( mode == SHADER_LINE_F ) - computeLineCoords( posture, -vs, vp, vec2( 1, 1 ), vec2( -1, 0 ), lineWidth, false ); - else if( mode == SHADER_FILLED_CIRCLE || mode == SHADER_STROKED_CIRCLE) - computeCircleCoords( mode, shaderParams.y, shaderParams.z, shaderParams.w ); - else - { - // Pass through the coordinates like in the fixed pipeline - gl_Position = ftransform(); - gl_FrontColor = gl_Color; - - } - - gl_Position.xy += antialiasingOffset; -} - -)SHADER_SOURCE"; - -const char kicad_fragment_shader[] = R"SHADER_SOURCE( - -/* - * This program source code file is part of KICAD, a free EDA CAD application. - * - * Copyright (C) 2013-2016 CERN - * Copyright (C) 2016 Kicad Developers, see authors.txt for contributors. - * @author Maciej Suminski - * - * Fragment shader - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you may find one here: - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * or you may search the http://www.gnu.org website for the version 2 license, - * or you may write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#version 120 - -// Multi-channel signed distance field -#define USE_MSDF - -// Shader types -const float SHADER_FILLED_CIRCLE = 2.0; -const float SHADER_STROKED_CIRCLE = 3.0; -const float SHADER_FONT = 4.0; -const float SHADER_LINE_A = 5.0; - -varying vec4 shaderParams; -varying vec2 circleCoords; -uniform sampler2D fontTexture; -uniform float worldPixelSize; - -// Needed to reconstruct the mipmap level / texel derivative -uniform int fontTextureWidth; - -void filledCircle( vec2 aCoord ) -{ - if( dot( aCoord, aCoord ) < 1.0 ) - gl_FragColor = gl_Color; - else - discard; -} - -float pixelSegDistance( vec2 aCoord ) -{ - float aspect = shaderParams[1]; - float dist; - vec2 v = vec2( 1.0 - ( aspect - abs( aCoord.s ) ), aCoord.t ); - - if( v.x <= 0.0 ) - { - dist = abs( aCoord.t ); - } - else - { - dist = length( v ); - } - - return dist; -} - -int isPixelInSegment( vec2 aCoord ) -{ - return pixelSegDistance( aCoord ) <= 1.0 ? 1 : 0; -} - - - -void strokedCircle( vec2 aCoord, float aRadius, float aWidth ) -{ - float outerRadius = max( aRadius, 0.0 ); - float innerRadius = max( aRadius - aWidth, 0.0 ); - - if( ( dot( aCoord, aCoord ) < 1.0 ) && - ( dot( aCoord, aCoord ) * ( outerRadius * outerRadius ) > innerRadius * innerRadius ) ) - gl_FragColor = gl_Color; - else - discard; -} - - -void drawLine( vec2 aCoord ) -{ - if( isPixelInSegment( aCoord ) != 0) - gl_FragColor = gl_Color; - else - discard; -} - -#ifdef USE_MSDF -float median( vec3 v ) -{ - return max( min( v.r, v.g ), min( max( v.r, v.g ), v.b ) ); -} -#endif - -void main() -{ - // VS to FS pipeline does math that means we can't rely on the mode - // parameter being bit-exact without rounding it first. - float mode = floor( shaderParams[0] + 0.5 ); - - if( mode == SHADER_LINE_A ) - { - drawLine( gl_TexCoord[0].st ); - } - else if( mode == SHADER_FILLED_CIRCLE ) - { - filledCircle( circleCoords ); - } - else if( mode == SHADER_STROKED_CIRCLE ) - { - strokedCircle( circleCoords, shaderParams[2], shaderParams[3] ); - } - else if( mode == SHADER_FONT ) - { - vec2 tex = shaderParams.yz; - - // Unless we're stretching chars it is okay to consider - // one derivative for filtering - float derivative = length( dFdx( tex ) ) * fontTextureWidth / 4; - -#ifdef USE_MSDF - float dist = median( texture2D( fontTexture, tex ).rgb ); -#else - float dist = texture2D( fontTexture, tex ).r; -#endif - - // use the derivative for zoom-adaptive filtering - float alpha = smoothstep( 0.5 - derivative, 0.5 + derivative, dist ) * gl_Color.a; - - gl_FragColor = vec4( gl_Color.rgb, alpha ); - } - else - { - // Simple pass-through - gl_FragColor = gl_Color; - } -} - -)SHADER_SOURCE"; - -const char ssaa_x4_vertex_shader[] = R"SHADER_SOURCE( - -#version 120 -varying vec2 texcoord; -void main() -{ - texcoord = gl_MultiTexCoord0.st; - gl_Position = ftransform(); -} - -)SHADER_SOURCE"; - const char ssaa_x4_fragment_shader[] = R"SHADER_SOURCE( #version 120 diff --git a/common/gal/opengl/gl_builtin_shaders.h b/common/gal/opengl/gl_builtin_shaders.h index b4998a06c3..769dcd234c 100644 --- a/common/gal/opengl/gl_builtin_shaders.h +++ b/common/gal/opengl/gl_builtin_shaders.h @@ -28,9 +28,6 @@ namespace KIGFX { namespace BUILTIN_SHADERS { - extern const char kicad_vertex_shader[]; - extern const char kicad_fragment_shader[]; - extern const char ssaa_x4_vertex_shader[]; extern const char ssaa_x4_fragment_shader[]; diff --git a/common/gal/opengl/opengl_gal.cpp b/common/gal/opengl/opengl_gal.cpp index ca26545be0..05067860a4 100644 --- a/common/gal/opengl/opengl_gal.cpp +++ b/common/gal/opengl/opengl_gal.cpp @@ -72,7 +72,8 @@ using namespace KIGFX; // The current font is "Ubuntu Mono" available under Ubuntu Font Licence 1.0 // (see ubuntu-font-licence-1.0.txt for details) #include "gl_resources.h" -#include "gl_builtin_shaders.h" +#include +#include using namespace KIGFX::BUILTIN_FONT; static void InitTesselatorCallbacks( GLUtesselator* aTesselator ); @@ -2302,14 +2303,14 @@ void OPENGL_GAL::init() // Prepare shaders if( !m_shader->IsLinked() && !m_shader->LoadShaderFromStrings( SHADER_TYPE_VERTEX, - BUILTIN_SHADERS::kicad_vertex_shader ) ) + BUILTIN_SHADERS::glsl_kicad_vert_shader ) ) { throw std::runtime_error( "Cannot compile vertex shader!" ); } if( !m_shader->IsLinked() && !m_shader->LoadShaderFromStrings( SHADER_TYPE_FRAGMENT, - BUILTIN_SHADERS::kicad_fragment_shader ) ) + BUILTIN_SHADERS::glsl_kicad_frag_shader ) ) { throw std::runtime_error( "Cannot compile fragment shader!" ); } diff --git a/common/gal/shaders/kicad_frag.glsl b/common/gal/shaders/kicad_frag.glsl new file mode 100644 index 0000000000..2769da4471 --- /dev/null +++ b/common/gal/shaders/kicad_frag.glsl @@ -0,0 +1,150 @@ +/* + * This program source code file is part of KICAD, a free EDA CAD application. + * + * Copyright (C) 2013-2016 CERN + * Copyright (C) 2016 Kicad Developers, see authors.txt for contributors. + * @author Maciej Suminski + * + * Fragment shader + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#version 120 + +// Multi-channel signed distance field +#define USE_MSDF + +// Shader types +const float SHADER_FILLED_CIRCLE = 2.0; +const float SHADER_STROKED_CIRCLE = 3.0; +const float SHADER_FONT = 4.0; +const float SHADER_LINE_A = 5.0; + +varying vec4 shaderParams; +varying vec2 circleCoords; +uniform sampler2D fontTexture; +uniform float worldPixelSize; + +// Needed to reconstruct the mipmap level / texel derivative +uniform int fontTextureWidth; + +void filledCircle( vec2 aCoord ) +{ + if( dot( aCoord, aCoord ) < 1.0 ) + gl_FragColor = gl_Color; + else + discard; +} + +float pixelSegDistance( vec2 aCoord ) +{ + float aspect = shaderParams[1]; + float dist; + vec2 v = vec2( 1.0 - ( aspect - abs( aCoord.s ) ), aCoord.t ); + + if( v.x <= 0.0 ) + { + dist = abs( aCoord.t ); + } + else + { + dist = length( v ); + } + + return dist; +} + +int isPixelInSegment( vec2 aCoord ) +{ + return pixelSegDistance( aCoord ) <= 1.0 ? 1 : 0; +} + + + +void strokedCircle( vec2 aCoord, float aRadius, float aWidth ) +{ + float outerRadius = max( aRadius, 0.0 ); + float innerRadius = max( aRadius - aWidth, 0.0 ); + + if( ( dot( aCoord, aCoord ) < 1.0 ) && + ( dot( aCoord, aCoord ) * ( outerRadius * outerRadius ) > innerRadius * innerRadius ) ) + gl_FragColor = gl_Color; + else + discard; +} + + +void drawLine( vec2 aCoord ) +{ + if( isPixelInSegment( aCoord ) != 0) + gl_FragColor = gl_Color; + else + discard; +} + +#ifdef USE_MSDF +float median( vec3 v ) +{ + return max( min( v.r, v.g ), min( max( v.r, v.g ), v.b ) ); +} +#endif + +void main() +{ + // VS to FS pipeline does math that means we can't rely on the mode + // parameter being bit-exact without rounding it first. + float mode = floor( shaderParams[0] + 0.5 ); + + if( mode == SHADER_LINE_A ) + { + drawLine( gl_TexCoord[0].st ); + } + else if( mode == SHADER_FILLED_CIRCLE ) + { + filledCircle( circleCoords ); + } + else if( mode == SHADER_STROKED_CIRCLE ) + { + strokedCircle( circleCoords, shaderParams[2], shaderParams[3] ); + } + else if( mode == SHADER_FONT ) + { + vec2 tex = shaderParams.yz; + + // Unless we're stretching chars it is okay to consider + // one derivative for filtering + float derivative = length( dFdx( tex ) ) * fontTextureWidth / 4; + +#ifdef USE_MSDF + float dist = median( texture2D( fontTexture, tex ).rgb ); +#else + float dist = texture2D( fontTexture, tex ).r; +#endif + + // use the derivative for zoom-adaptive filtering + float alpha = smoothstep( 0.5 - derivative, 0.5 + derivative, dist ) * gl_Color.a; + + gl_FragColor = vec4( gl_Color.rgb, alpha ); + } + else + { + // Simple pass-through + gl_FragColor = gl_Color; + } +} \ No newline at end of file diff --git a/common/gal/shaders/kicad_vert.glsl b/common/gal/shaders/kicad_vert.glsl new file mode 100644 index 0000000000..110f02c9ed --- /dev/null +++ b/common/gal/shaders/kicad_vert.glsl @@ -0,0 +1,208 @@ +/* + * This program source code file is part of KICAD, a free EDA CAD application. + * + * Copyright (C) 2013-2016 CERN + * @author Maciej Suminski + * + * Vertex shader + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#version 120 + +// Shader types +const float SHADER_FILLED_CIRCLE = 2.0; +const float SHADER_STROKED_CIRCLE = 3.0; +const float SHADER_FONT = 4.0; +const float SHADER_LINE_A = 5.0; +const float SHADER_LINE_B = 6.0; +const float SHADER_LINE_C = 7.0; +const float SHADER_LINE_D = 8.0; +const float SHADER_LINE_E = 9.0; +const float SHADER_LINE_F = 10.0; + +// Minimum line width +const float MIN_WIDTH = 1.0; + +attribute vec4 attrShaderParams; +varying vec4 shaderParams; +varying vec2 circleCoords; +uniform float worldPixelSize; +uniform vec2 screenPixelSize; +uniform float pixelSizeMultiplier; +uniform float minLinePixelWidth; +uniform vec2 antialiasingOffset; + + +float roundr( float f, float r ) +{ + return floor(f / r + 0.5) * r; +} + +vec4 roundv( vec4 x, vec2 t) +{ + return vec4( roundr(x.x, t.x), roundr(x.y, t.y), x.z, x.w ); +} + +void computeLineCoords( bool posture, vec2 vs, vec2 vp, vec2 texcoord, vec2 dir, float lineWidth, bool endV ) +{ + float lineLength = length(vs); + vec4 screenPos = gl_ModelViewProjectionMatrix * gl_Vertex + vec4(1, 1, 0, 0); + float w = ((lineWidth == 0.0) ? worldPixelSize : lineWidth ); + float pixelWidth = roundr( w / worldPixelSize, 1.0 ); + float aspect = ( lineLength + w ) / w; + vec4 color = gl_Color; + vec2 s = sign( vec2( gl_ModelViewProjectionMatrix[0][0], gl_ModelViewProjectionMatrix[1][1] ) ); + + + if( pixelWidth < 1.0 ) + pixelWidth = 1.0; + + if ( pixelWidth > 1.0 || pixelSizeMultiplier > 1.0 ) + { + vec2 offsetNorm = (vs + vp) * pixelWidth / lineLength * 0.5; + vec4 screenOffset = vec4( s.x * offsetNorm.x * screenPixelSize.x, s.y * offsetNorm.y * screenPixelSize.y , 0, 0); + vec4 adjust = vec4(-1, -1, 0, 0); + + if( mod( pixelWidth * pixelSizeMultiplier, 2.0 ) > 0.9 ) + { + adjust += vec4( screenPixelSize.x, screenPixelSize.y, 0, 0 ) * 0.5; + } + + gl_Position = roundv(screenPos, screenPixelSize) + adjust + screenOffset; + + shaderParams[0] = SHADER_LINE_A; + } + else { + vec4 pos0 = screenPos; + pos0.xy += ( posture ? dir.xy : dir.yx ) * screenPixelSize / 2.0; + + if(posture) + { + pos0.y -= screenPixelSize.y * sign(vs.y) * 0.5; + } + else + { + pos0.x += screenPixelSize.x * sign(vs.x) * 0.5; + } + + gl_Position = pos0 - vec4(1, 1, 0, 0); + shaderParams[0] = SHADER_LINE_B; + } + + shaderParams[1] = aspect; + + gl_TexCoord[0].st = vec2(aspect * texcoord.x, texcoord.y); + gl_FrontColor = gl_Color; +} + + +void computeCircleCoords( float mode, float vertexIndex, float radius, float lineWidth ) +{ + vec4 delta; + vec4 center = roundv( gl_ModelViewProjectionMatrix * gl_Vertex + vec4(1, 1, 0, 0), screenPixelSize ); + float pixelWidth = roundr( lineWidth / worldPixelSize, 1.0); + float pixelR = roundr( radius / worldPixelSize, 1.0); + + if( mode == SHADER_STROKED_CIRCLE) + pixelR += pixelWidth / 2.0; + + vec4 adjust = vec4(-1, -1, 0, 0); + + if( pixelWidth < 1.0 ) + pixelWidth = 1.0; + + if( vertexIndex == 1.0 ) + { + circleCoords = vec2( -sqrt( 3.0 ), -1.0 ); + delta = vec4( -pixelR * sqrt(3.0), -pixelR, 0, 0 ); + } + else if( vertexIndex == 2.0 ) + { + circleCoords = vec2( sqrt( 3.0 ), -1.0 ); + delta = vec4( pixelR * sqrt( 3.0 ), -pixelR, 0, 0 ); + } + else if( vertexIndex == 3.0 ) + { + circleCoords = vec2( 0.0, 2.0 ); + delta = vec4( 0, 2 * pixelR, 0, 0 ); + } + else if( vertexIndex == 4.0 ) + { + circleCoords = vec2( -sqrt( 3.0 ), 0.0 ); + delta = vec4( 0, 0, 0, 0 ); + } + else if( vertexIndex == 5.0 ) + { + circleCoords = vec2( sqrt( 3.0 ), 0.0 ); + delta = vec4( 0, 0, 0, 0 ); + } + else if( vertexIndex == 6.0 ) + { + circleCoords = vec2( 0.0, 2.0 ); + delta = vec4( 0, 0, 0, 0 ); + } + + shaderParams[2] = pixelR; + shaderParams[3] = pixelWidth; + + delta.x *= screenPixelSize.x; + delta.y *= screenPixelSize.y; + + gl_Position = center + delta + adjust; + gl_FrontColor = gl_Color; +} + + +void main() +{ + float mode = attrShaderParams[0]; + + // Pass attributes to the fragment shader + shaderParams = attrShaderParams; + + float lineWidth = shaderParams.y; + vec2 vs = shaderParams.zw; + vec2 vp = vec2(-vs.y, vs.x); + bool posture = abs( vs.x ) < abs(vs.y); + + if( mode == SHADER_LINE_A ) + computeLineCoords( posture, -vs, vp, vec2( -1, -1 ), vec2( -1, 0 ), lineWidth, false ); + else if( mode == SHADER_LINE_B ) + computeLineCoords( posture, -vs, -vp, vec2( -1, 1 ), vec2( 1, 0 ), lineWidth, false ); + else if( mode == SHADER_LINE_C ) + computeLineCoords( posture, vs, -vp, vec2( 1, 1 ), vec2( 1, 0 ), lineWidth, true ); + else if( mode == SHADER_LINE_D ) + computeLineCoords( posture, vs, -vp, vec2( -1, -1 ), vec2( 1, 0 ), lineWidth, true ); + else if( mode == SHADER_LINE_E ) + computeLineCoords( posture, vs, vp, vec2( -1, 1 ), vec2( -1, 0 ), lineWidth, true ); + else if( mode == SHADER_LINE_F ) + computeLineCoords( posture, -vs, vp, vec2( 1, 1 ), vec2( -1, 0 ), lineWidth, false ); + else if( mode == SHADER_FILLED_CIRCLE || mode == SHADER_STROKED_CIRCLE) + computeCircleCoords( mode, shaderParams.y, shaderParams.z, shaderParams.w ); + else + { + // Pass through the coordinates like in the fixed pipeline + gl_Position = ftransform(); + gl_FrontColor = gl_Color; + + } + + gl_Position.xy += antialiasingOffset; +} \ No newline at end of file