From 9b5d364add330fc18100491bf3c57316a27183f5 Mon Sep 17 00:00:00 2001 From: David Thompson Date: Fri, 27 Aug 2021 16:07:38 -0400 Subject: graphics: path: Separate fill/stroke into different shaders. --- Makefile.am | 6 ++- chickadee/graphics/path.scm | 22 ++++----- data/shaders/path-fill-frag.glsl | 17 +++++++ data/shaders/path-fill-vert.glsl | 22 +++++++++ data/shaders/path-frag.glsl | 93 -------------------------------------- data/shaders/path-stroke-frag.glsl | 77 +++++++++++++++++++++++++++++++ data/shaders/path-stroke-vert.glsl | 39 ++++++++++++++++ data/shaders/path-vert.glsl | 44 ------------------ 8 files changed, 170 insertions(+), 150 deletions(-) create mode 100644 data/shaders/path-fill-frag.glsl create mode 100644 data/shaders/path-fill-vert.glsl delete mode 100644 data/shaders/path-frag.glsl create mode 100644 data/shaders/path-stroke-frag.glsl create mode 100644 data/shaders/path-stroke-vert.glsl delete mode 100644 data/shaders/path-vert.glsl diff --git a/Makefile.am b/Makefile.am index 338a009..0c10d13 100644 --- a/Makefile.am +++ b/Makefile.am @@ -133,8 +133,10 @@ dist_fonts_DATA = \ shadersdir = $(pkgdatadir)/shaders dist_shaders_DATA = \ - data/shaders/path-vert.glsl \ - data/shaders/path-frag.glsl \ + data/shaders/path-fill-frag.glsl \ + data/shaders/path-fill-vert.glsl \ + data/shaders/path-stroke-frag.glsl \ + data/shaders/path-stroke-vert.glsl \ data/shaders/pbr-vert.glsl \ data/shaders/pbr-frag.glsl \ data/shaders/phong-vert.glsl \ diff --git a/chickadee/graphics/path.scm b/chickadee/graphics/path.scm index fb75efd..edce792 100644 --- a/chickadee/graphics/path.scm +++ b/chickadee/graphics/path.scm @@ -1087,9 +1087,13 @@ ;;; Rendering ;;; -(define-graphics-variable path-shader - (load-shader (scope-datadir "shaders/path-vert.glsl") - (scope-datadir "shaders/path-frag.glsl"))) +(define-graphics-variable stroke-shader + (load-shader (scope-datadir "shaders/path-stroke-vert.glsl") + (scope-datadir "shaders/path-stroke-frag.glsl"))) + +(define-graphics-variable fill-shader + (load-shader (scope-datadir "shaders/path-fill-vert.glsl") + (scope-datadir "shaders/path-fill-frag.glsl"))) (define-graphics-variable mvp-matrix (make-null-matrix4)) @@ -1104,7 +1108,7 @@ ;; TODO: gradients (define* (draw-filled-path filled-path matrix) - (let ((shader (graphics-variable-ref path-shader)) + (let ((shader (graphics-variable-ref fill-shader)) (mvp (graphics-variable-ref mvp-matrix)) (counts (filled-path-counts filled-path)) (offsets (filled-path-offsets filled-path)) @@ -1120,8 +1124,7 @@ (geometry-vertex-array stencil-geometry) (u32vector-ref offsets i) (u32vector-ref counts i) - #:mvp (current-projection) - #:mode 0)))) + #:mvp (current-projection))))) ;; Anti-alias the edges of the fill. (with-graphics-state ((g:multisample? #t)) ;; Render fan to stencil buffer. Each time a triangle is @@ -1142,8 +1145,7 @@ (geometry-vertex-array stencil-geometry) (u32vector-ref offsets i) (u32vector-ref counts i) - #:mvp mvp - #:mode 0))) + #:mvp mvp))) ;; Render a quad with the stencil applied. The quad is the size ;; of the path's bounding box. The stencil test will make it so ;; we only draw fragments that are part of the filled path. @@ -1152,13 +1154,12 @@ (shader-apply shader (geometry-vertex-array quad-geometry) #:mvp mvp - #:mode 0 #:color (filled-path-color filled-path)))))) ;; TODO: dashed stroke ;; TODO: miter styles and miter limit (define* (draw-stroked-path stroked-path matrix) - (let ((shader (graphics-variable-ref path-shader)) + (let ((shader (graphics-variable-ref stroke-shader)) (mvp (graphics-variable-ref mvp-matrix))) (matrix4-mult! mvp matrix (current-projection)) (with-graphics-state ((g:blend-mode (stroked-path-blend-mode stroked-path))) @@ -1169,7 +1170,6 @@ (geometry-index-count geometry) #:mvp mvp #:color (stroked-path-color stroked-path) - #:mode 1 #:feather (stroked-path-feather stroked-path) #:stroke-cap (match (stroked-path-cap stroked-path) (#f 0) ; no cap diff --git a/data/shaders/path-fill-frag.glsl b/data/shaders/path-fill-frag.glsl new file mode 100644 index 0000000..3af191f --- /dev/null +++ b/data/shaders/path-fill-frag.glsl @@ -0,0 +1,17 @@ +// -*- mode: c -*- + +#ifdef GLSL330 +out vec4 fragColor; +#else +#define fragColor gl_FragColor +#endif + +uniform vec4 color; + +void main(void) { + if (color.a <= 0.0) { + discard; + } + + fragColor = color; +} diff --git a/data/shaders/path-fill-vert.glsl b/data/shaders/path-fill-vert.glsl new file mode 100644 index 0000000..d95b71b --- /dev/null +++ b/data/shaders/path-fill-vert.glsl @@ -0,0 +1,22 @@ +// -*- mode: c -*- + +#ifdef GLSL330 +layout (location = 0) in vec2 position; +#elif defined(GLSL130) +in vec2 position; +#elif defined(GLSL120) +attribute vec2 position; +#endif + +uniform mat4 mvp; +uniform vec4 color; + +void main(void) { + // Short-circuit because the fragments will just be discarded + // anyway. + if (color.a <= 0.0) { + gl_Position = vec4(0.0, 0.0, 0.0, 1.0); + } else { + gl_Position = mvp * vec4(position.xy, 0.0, 1.0); + } +} diff --git a/data/shaders/path-frag.glsl b/data/shaders/path-frag.glsl deleted file mode 100644 index 0288ae1..0000000 --- a/data/shaders/path-frag.glsl +++ /dev/null @@ -1,93 +0,0 @@ -// -*- mode: c -*- - -#ifdef GLSL330 -out vec4 fragColor; -#endif - -#ifdef GLSL120 -varying vec2 fragTex; -varying float fragStrokeLength; -#else -in vec2 fragTex; -in float fragStrokeLength; -#endif - -uniform int mode; -uniform vec4 color; -uniform float feather; -uniform int strokeClosed; -uniform float strokeWidth; -uniform int strokeCap; -uniform int strokeMiterStyle; -uniform float strokeMiterLimit; - -float infinity = 1.0 / 0.0; - -void main(void) { - if (color.a <= 0.0) { - discard; - } - - // fill mode - if(mode == 0) { -#ifdef GLSL330 - fragColor = color; -#else - gl_FragColor = color; -#endif - } else if(mode == 1) { // stroke mode - float hw = strokeWidth / 2.0; - float u = fragTex.x; - float v = fragTex.y; - float dx; - float dy; - float d; - - // Stroke caps. - if (u < 0 || u > fragStrokeLength) { - if (u < 0) { - dx = abs(u); - } else { - dx = u - fragStrokeLength; - } - dy = abs(v); - - if (strokeCap == 0) { // none - d = infinity; - } else if (strokeCap == 1) { // butt - d = max(dx + hw - 2 * feather, dy); - } else if (strokeCap == 2) { // square - d = max(dx, dy); - } else if (strokeCap == 3) { // round - d = sqrt(dx * dx + dy * dy); - } else if (strokeCap == 4) { // triangle out - d = dx + dy; - } else if (strokeCap == 5) { // triangle in - d = max(dy, hw - feather + dx - dy); - } - // Stroke inner/join - } else { - d = abs(v); - } - - if(d <= hw) { -#ifdef GLSL330 - fragColor = color; -#else - gl_FragColor = color; -#endif - } else { - vec4 c = vec4(color.rgb, color.a * (1.0 - ((d - hw) / feather))); - - if (c.a <= 0.0) { - discard; - } - -#ifdef GLSL330 - fragColor = c; -#else - gl_FragColor = c; -#endif - } - } -} diff --git a/data/shaders/path-stroke-frag.glsl b/data/shaders/path-stroke-frag.glsl new file mode 100644 index 0000000..9682c8f --- /dev/null +++ b/data/shaders/path-stroke-frag.glsl @@ -0,0 +1,77 @@ +// -*- mode: c -*- + +#ifdef GLSL330 +out vec4 fragColor; +#else +#define fragColor gl_FragColor +#endif + +#ifdef GLSL120 +varying vec2 fragTex; +varying float fragStrokeLength; +#else +in vec2 fragTex; +in float fragStrokeLength; +#endif + +uniform vec4 color; +uniform float feather; +uniform int strokeClosed; +uniform float strokeWidth; +uniform int strokeCap; +uniform int strokeMiterStyle; +uniform float strokeMiterLimit; + +float infinity = 1.0 / 0.0; + +void main(void) { + if (color.a <= 0.0) { + discard; + } + + float hw = strokeWidth / 2.0; + float u = fragTex.x; + float v = fragTex.y; + float dx; + float dy; + float d; + + // Stroke caps. + if (u < 0 || u > fragStrokeLength) { + if (u < 0) { + dx = abs(u); + } else { + dx = u - fragStrokeLength; + } + dy = abs(v); + + if (strokeCap == 0) { // none + d = infinity; + } else if (strokeCap == 1) { // butt + d = max(dx + hw - 2 * feather, dy); + } else if (strokeCap == 2) { // square + d = max(dx, dy); + } else if (strokeCap == 3) { // round + d = sqrt(dx * dx + dy * dy); + } else if (strokeCap == 4) { // triangle out + d = dx + dy; + } else if (strokeCap == 5) { // triangle in + d = max(dy, hw - feather + dx - dy); + } + // Stroke inner/join + } else { + d = abs(v); + } + + if(d <= hw) { + fragColor = color; + } else { + vec4 c = vec4(color.rgb, color.a * (1.0 - ((d - hw) / feather))); + + if (c.a <= 0.0) { + discard; + } + + fragColor = c; + } +} diff --git a/data/shaders/path-stroke-vert.glsl b/data/shaders/path-stroke-vert.glsl new file mode 100644 index 0000000..5915010 --- /dev/null +++ b/data/shaders/path-stroke-vert.glsl @@ -0,0 +1,39 @@ +// -*- mode: c -*- + +#ifdef GLSL330 +layout (location = 0) in vec2 position; +layout (location = 1) in vec2 tex; +layout (location = 2) in float strokeLength; +#elif defined(GLSL130) +in vec2 position; +in vec2 tex; +in float strokeLength; +#elif defined(GLSL120) +attribute vec2 position; +attribute vec2 tex; +attribute float strokeLength; +#endif + +#ifdef GLSL120 +varying vec2 fragTex; +varying float fragStrokeLength; +#else +out vec2 fragTex; +out float fragStrokeLength; +#endif + +uniform mat4 mvp; +uniform vec4 color; +uniform int mode; +uniform int strokeClosed; + +void main(void) { + // Short-circuit because the fragments will just be discarded anyway. + if (color.a <= 0.0) { + gl_Position = vec4(0.0, 0.0, 0.0, 1.0); + } else { + fragStrokeLength = strokeLength; + fragTex = tex; + gl_Position = mvp * vec4(position.xy, 0.0, 1.0); + } +} diff --git a/data/shaders/path-vert.glsl b/data/shaders/path-vert.glsl deleted file mode 100644 index 38fa5d2..0000000 --- a/data/shaders/path-vert.glsl +++ /dev/null @@ -1,44 +0,0 @@ -// -*- mode: c -*- - -#ifdef GLSL330 -layout (location = 0) in vec2 position; -layout (location = 1) in vec2 tex; -layout (location = 2) in float strokeLength; -#elif defined(GLSL130) -in vec2 position; -in vec2 tex; -in float strokeLength; -#elif defined(GLSL120) -attribute vec2 position; -attribute vec2 tex; -attribute float strokeLength; -#endif - -#ifdef GLSL120 -varying vec2 fragTex; -varying float fragStrokeLength; -#else -out vec2 fragTex; -out float fragStrokeLength; -#endif - -uniform mat4 mvp; -uniform vec4 color; -uniform int mode; -uniform int strokeClosed; - -void main(void) { - // Short-circuit because the fragments will just be discarded anyway. - if (color.a <= 0.0) { - gl_Position = vec4(0.0, 0.0, 0.0, 1.0); - return; - } - - // Stroke specific setup. - if (mode == 1) { - fragStrokeLength = strokeLength; - } - - fragTex = tex; - gl_Position = mvp * vec4(position.xy, 0.0, 1.0); -} -- cgit v1.2.3