7 changed files with 426 additions and 397 deletions
-
35CMakeModules/BuildSteps/CreateShaderCpp.cmake
-
34common/gal/CMakeLists.txt
-
386common/gal/opengl/gl_builtin_shaders.cpp
-
3common/gal/opengl/gl_builtin_shaders.h
-
7common/gal/opengl/opengl_gal.cpp
-
150common/gal/shaders/kicad_frag.glsl
-
208common/gal/shaders/kicad_vert.glsl
@ -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}") |
||||
@ -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 <maciej.suminski@cern.ch> |
||||
|
* |
||||
|
* 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; |
||||
|
} |
||||
|
} |
||||
@ -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 <maciej.suminski@cern.ch> |
||||
|
* |
||||
|
* 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; |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue