mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-25 21:21:21 +00:00
vulkan: Rewrite rounded rectangle to use SDF distance
We can use this to properly compute distance in scaled situations. We also now compute coverage with (imperfect) antialiasing.
This commit is contained in:
parent
64bcdb713c
commit
1be21a33d9
@ -1,5 +1,5 @@
|
||||
#include "constants.glsl"
|
||||
#include "rounded-rect.glsl"
|
||||
#include "rounded-rect.frag.glsl"
|
||||
|
||||
#ifndef _CLIP_
|
||||
#define _CLIP_
|
||||
|
38
gsk/vulkan/resources/ellipse.glsl
Normal file
38
gsk/vulkan/resources/ellipse.glsl
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef _ELLIPSE_
|
||||
#define _ELLIPSE_
|
||||
|
||||
struct Ellipse
|
||||
{
|
||||
vec2 center;
|
||||
vec2 radius;
|
||||
};
|
||||
|
||||
float
|
||||
ellipse_distance (Ellipse r, vec2 p)
|
||||
{
|
||||
vec2 e = r.radius;
|
||||
p = p - r.center;
|
||||
|
||||
if (e.x == e.y)
|
||||
return length (p) - e.x;
|
||||
|
||||
/* from https://www.shadertoy.com/view/tt3yz7 */
|
||||
vec2 pAbs = abs(p);
|
||||
vec2 ei = 1.0 / e;
|
||||
vec2 e2 = e*e;
|
||||
vec2 ve = ei * vec2(e2.x - e2.y, e2.y - e2.x);
|
||||
|
||||
vec2 t = vec2(0.70710678118654752, 0.70710678118654752);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
vec2 v = ve*t*t*t;
|
||||
vec2 u = normalize(pAbs - v) * length(t * e - v);
|
||||
vec2 w = ei * (v + u);
|
||||
t = normalize(clamp(w, 0.0, 1.0));
|
||||
}
|
||||
|
||||
vec2 nearestAbs = t * e;
|
||||
float dist = length(pAbs - nearestAbs);
|
||||
return dot(pAbs, pAbs) < dot(nearestAbs, nearestAbs) ? -dist : dist;
|
||||
}
|
||||
|
||||
#endif
|
@ -6,6 +6,7 @@ gsk_private_vulkan_include_shaders = [
|
||||
'rect.frag.glsl',
|
||||
'rect.vert.glsl',
|
||||
'rounded-rect.glsl',
|
||||
'rounded-rect.frag.glsl',
|
||||
]
|
||||
|
||||
gsk_private_vulkan_fragment_shaders = [
|
||||
|
17
gsk/vulkan/resources/rounded-rect.frag.glsl
Normal file
17
gsk/vulkan/resources/rounded-rect.frag.glsl
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef _ROUNDED_RECT_FRAG_
|
||||
#define _ROUNDED_RECT_FRAG_
|
||||
|
||||
#include "rounded-rect.glsl"
|
||||
|
||||
float
|
||||
rounded_rect_coverage (RoundedRect r, vec2 p)
|
||||
{
|
||||
vec2 fw = abs (fwidth (p));
|
||||
float distance_scale = max (fw.x, fw.y);
|
||||
float distance = rounded_rect_distance (r, p) / distance_scale;
|
||||
float coverage = 0.5 - distance;
|
||||
|
||||
return clamp (coverage, 0, 1);
|
||||
}
|
||||
|
||||
#endif
|
@ -1,6 +1,9 @@
|
||||
#ifndef _ROUNDED_RECT_
|
||||
#define _ROUNDED_RECT_
|
||||
|
||||
#include "ellipse.glsl"
|
||||
#include "rect.glsl"
|
||||
|
||||
struct RoundedRect
|
||||
{
|
||||
vec4 bounds;
|
||||
@ -9,51 +12,34 @@ struct RoundedRect
|
||||
};
|
||||
|
||||
float
|
||||
ellipsis_dist (vec2 p, vec2 radius)
|
||||
rounded_rect_distance (RoundedRect r, vec2 p)
|
||||
{
|
||||
vec2 p0 = p / radius;
|
||||
vec2 p1 = 2.0 * p0 / radius;
|
||||
|
||||
return (dot(p0, p0) - 1.0) / length (p1);
|
||||
}
|
||||
Rect bounds = Rect(vec4(r.bounds));
|
||||
|
||||
float
|
||||
ellipsis_coverage (vec2 point, vec2 center, vec2 radius)
|
||||
{
|
||||
float d = ellipsis_dist (point - center, radius);
|
||||
return clamp (0.5 - d, 0.0, 1.0);
|
||||
}
|
||||
|
||||
float
|
||||
rounded_rect_coverage (RoundedRect r, vec2 p)
|
||||
{
|
||||
if (p.x < r.bounds.x || p.y < r.bounds.y ||
|
||||
p.x >= r.bounds.z || p.y >= r.bounds.w)
|
||||
return 0.0;
|
||||
float bounds_distance = rect_distance (bounds, p);
|
||||
|
||||
vec2 rad_tl = vec2(r.corner_widths.x, r.corner_heights.x);
|
||||
vec2 rad_tr = vec2(r.corner_widths.y, r.corner_heights.y);
|
||||
vec2 rad_br = vec2(r.corner_widths.z, r.corner_heights.z);
|
||||
vec2 rad_bl = vec2(r.corner_widths.w, r.corner_heights.w);
|
||||
|
||||
vec2 ref_tl = r.bounds.xy + vec2( r.corner_widths.x, r.corner_heights.x);
|
||||
vec2 ref_tr = r.bounds.zy + vec2(-r.corner_widths.y, r.corner_heights.y);
|
||||
vec2 ref_br = r.bounds.zw + vec2(-r.corner_widths.z, -r.corner_heights.z);
|
||||
vec2 ref_bl = r.bounds.xw + vec2( r.corner_widths.w, -r.corner_heights.w);
|
||||
Ellipse tl = Ellipse (r.bounds.xy + vec2( r.corner_widths.x, r.corner_heights.x),
|
||||
vec2(r.corner_widths.x, r.corner_heights.x));
|
||||
Ellipse tr = Ellipse (r.bounds.zy + vec2(-r.corner_widths.y, r.corner_heights.y),
|
||||
vec2(r.corner_widths.y, r.corner_heights.y));
|
||||
Ellipse br = Ellipse (r.bounds.zw + vec2(-r.corner_widths.z, -r.corner_heights.z),
|
||||
vec2(r.corner_widths.z, r.corner_heights.z));
|
||||
Ellipse bl = Ellipse (r.bounds.xw + vec2( r.corner_widths.w, -r.corner_heights.w),
|
||||
vec2(r.corner_widths.w, r.corner_heights.w));
|
||||
|
||||
float d_tl = ellipsis_coverage(p, ref_tl, rad_tl);
|
||||
float d_tr = ellipsis_coverage(p, ref_tr, rad_tr);
|
||||
float d_br = ellipsis_coverage(p, ref_br, rad_br);
|
||||
float d_bl = ellipsis_coverage(p, ref_bl, rad_bl);
|
||||
vec4 distances = vec4(ellipse_distance (tl, p),
|
||||
ellipse_distance (tr, p),
|
||||
ellipse_distance (br, p),
|
||||
ellipse_distance (bl, p));
|
||||
|
||||
vec4 corner_coverages = 1.0 - vec4(d_tl, d_tr, d_br, d_bl);
|
||||
bvec4 is_out = bvec4(p.x < tl.center.x && p.y < tl.center.y,
|
||||
p.x > tr.center.x && p.y < tr.center.y,
|
||||
p.x > br.center.x && p.y > br.center.y,
|
||||
p.x < bl.center.x && p.y > bl.center.y);
|
||||
distances = mix (vec4(bounds_distance), distances, is_out);
|
||||
|
||||
bvec4 is_out = bvec4(p.x < ref_tl.x && p.y < ref_tl.y,
|
||||
p.x > ref_tr.x && p.y < ref_tr.y,
|
||||
p.x > ref_br.x && p.y > ref_br.y,
|
||||
p.x < ref_bl.x && p.y > ref_bl.y);
|
||||
|
||||
return 1.0 - dot(vec4(is_out), corner_coverages);
|
||||
vec2 max2 = max (distances.xy, distances.zw);
|
||||
return max (max2.x, max2.y);
|
||||
}
|
||||
|
||||
RoundedRect
|
||||
|
Loading…
Reference in New Issue
Block a user