diff --git a/src/scenegraph/shaders.qrc b/src/scenegraph/shaders.qrc index f0f8f22c..b9545645 100644 --- a/src/scenegraph/shaders.qrc +++ b/src/scenegraph/shaders.qrc @@ -1,11 +1,13 @@ header_es.glsl header_desktop.glsl header_desktop_core.glsl shadowedrectangle.vert + shadowedrectangle_core.vert shadowedrectangle.frag + shadowedrectangle_core.frag diff --git a/src/scenegraph/shadowedrectangle_core.frag b/src/scenegraph/shadowedrectangle_core.frag new file mode 100644 index 00000000..b7990584 --- /dev/null +++ b/src/scenegraph/shadowedrectangle_core.frag @@ -0,0 +1,80 @@ +/* + * Copyright 2020 Arjen Hiemstra + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, 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 Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +// This is based on the 2D SDF functions provided by Inigo Quilez: +// https://iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm + +uniform lowp float opacity; +uniform lowp float size; +uniform lowp float radius; +uniform lowp vec4 color; +uniform lowp vec4 shadowColor; +uniform lowp vec2 offset; +uniform lowp vec2 aspect; + +in lowp vec2 uv; + +const lowp float minimum_shadow_radius = 0.05; + +// Calculate the distance to a rectangle with rounded corners. +// \param point The point to calculate the distance of. +// \param rect The rectangle to calculate the distance of. +// \param translation The amount of translation to apply to the rectangle. +// \param radius A vec4 with the radius of each corner. +lowp float sdf_rounded_rectangle(in lowp vec2 point, in lowp vec2 rect, in lowp vec2 translation, in lowp vec4 radius) +{ + radius.xy = (point.x > 0.0) ? radius.xy : radius.zw; + radius.x = (point.y > 0.0) ? radius.x : radius.y; + lowp vec2 d = abs(point - translation) - rect + radius.x; + return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)) - radius.x; +} + +void main() +{ + // Scaling factor that is the inverse of the amount of scaling applied to the geometry. + lowp float inverse_scale = 1.0 / (1.0 + size + length(offset * 2.0)); + + // Correction factor to round the corners of a larger shadow. + // We want to account for size in regards to shadow radius, so that a larger shadow is + // more rounded, but only if we are not already rounding the corners due to corner radius. + lowp float size_factor = 0.5 * (minimum_shadow_radius / max(radius, minimum_shadow_radius)); + + lowp float shadowRadius = radius + size * size_factor; + + lowp vec4 col = vec4(0.0); + + // Calculate the shadow's distance field. + lowp float shadow = sdf_rounded_rectangle(uv, aspect * inverse_scale, offset * inverse_scale, vec4(shadowRadius * inverse_scale)); + // Render it, interpolating the color over the distance. + col = mix(col, shadowColor * sign(size), shadowColor.a * (1.0 - smoothstep(-size * 0.5, size * 0.5, shadow))); + + // Calculate the main rectangle distance field. + lowp float rect = sdf_rounded_rectangle(uv, aspect * inverse_scale, vec2(0.0), vec4(radius * inverse_scale)); + + lowp float g = fwidth(rect); + + // First, remove anything that was rendered by the shadow if it is inside the rectangle. + // This allows us to use colors with alpha without rendering artifacts. + col = mix(col, vec4(0.0), 1.0 - smoothstep(0.001 - g, 0.001 + g, rect)); + + // Then, render it again but this time with the proper color and properly alpha blended. + col = mix(col, color, color.a * (1.0 - smoothstep(0.001 - g, 0.001 + g, rect))); + + gl_FragColor = col * opacity; +} diff --git a/src/scenegraph/shadowedrectangle_core.vert b/src/scenegraph/shadowedrectangle_core.vert new file mode 100644 index 00000000..8daeaadb --- /dev/null +++ b/src/scenegraph/shadowedrectangle_core.vert @@ -0,0 +1,32 @@ +/* + * Copyright 2020 Arjen Hiemstra + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, 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 Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +uniform mat4 matrix; +uniform vec2 aspect; +uniform vec2 offset; + +in vec4 in_vertex; +in vec2 in_uv; + +out vec2 uv; + +void main() { + uv = (-1.0 + 2.0 * in_uv) * aspect; + gl_Position = matrix * in_vertex; +}