git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

scenefx/render/fx_renderer/shaders/corner_alpha.frag (3.4K)

 1 // Corner-shape exponent: 2 = circular arc, > 2 = superellipse "squircle"
 2 // corners — kept in lockstep with the cce-ui clients' corner_shape so the
 3 // compositor's corner cut lands exactly on the corners the clients draw.
 4 uniform float corner_shape;
 5 
 6 float get_dist(vec2 q, float radius) {
 7 	vec2 p = max(q, 0.0);
 8 	if (corner_shape > 2.001 && radius > 0.0 && p.x > 0.0 && p.y > 0.0) {
 9 		// Superellipse (Lp-norm) corner, radius-normalized so the pow()
10 		// arguments stay near 1 (mediump-safe). The Lp gradient is not unit
11 		// length, so the distance carries a first-order |grad| correction —
12 		// exact on the boundary, where the AA smoothstep samples it.
13 		vec2 u = p / radius;
14 		float lp = max(pow(pow(u.x, corner_shape) + pow(u.y, corner_shape),
15 			1.0 / corner_shape), 1e-4);
16 		vec2 g = vec2(pow(u.x / lp, corner_shape - 1.0),
17 			pow(u.y / lp, corner_shape - 1.0));
18 		return min(max(q.x, q.y), 0.0)
19 			+ radius * (lp - 1.0) / max(length(g), 1e-4);
20 	}
21 	return min(max(q.x, q.y), 0.0) + length(p) - radius;
22 }
23 
24 // Note: Returns 0.0 if outside, 1.0 if inside the bounds. The is_cutout parameter
25 // reverses this, 0.0 inside cutout and 1.0 for outside cutout.
26 float corner_alpha(vec2 size, vec2 position, bool is_cutout,
27 		float radius_tl, float radius_tr, float radius_bl, float radius_br) {
28 	if (radius_tl <= 0.0
29 			&& radius_tr <= 0.0
30 			&& radius_bl <= 0.0
31 			&& radius_br <= 0.0) {
32 		return 1.0;
33 	}
34 
35 	vec2 relative_pos = (gl_FragCoord.xy - position);
36 	relative_pos.y = size.y - relative_pos.y;
37 
38 	if (relative_pos.x < -0.5 || relative_pos.y < -0.5
39 			|| relative_pos.x > size.x + 0.5 || relative_pos.y > size.y + 0.5) {
40 		if (is_cutout) {
41 			return 1.0;
42 		}
43 		discard;
44 	}
45 
46 	bool is_top_left = radius_tl > 0.0
47 		&& relative_pos.x <= radius_tl
48 		&& relative_pos.y <= radius_tl;
49 	bool is_top_right = radius_tr > 0.0
50 		&& relative_pos.x >= size.x - radius_tr
51 		&& relative_pos.y <= radius_tr;
52 	bool is_bottom_left = radius_bl > 0.0
53 		&& relative_pos.x <= radius_bl
54 		&& relative_pos.y >= size.y - radius_bl;
55 	bool is_bottom_right = radius_br > 0.0
56 		&& relative_pos.x >= size.x - radius_br
57 		&& relative_pos.y >= size.y - radius_br;
58 	if (!is_top_left && !is_top_right && !is_bottom_left && !is_bottom_right) {
59 		if (is_cutout) {
60 			discard;
61 		}
62 		return 1.0;
63 	}
64 
65 	vec2 top_left = abs(relative_pos - size) - size + radius_tl;
66 	vec2 top_right = abs(relative_pos - vec2(0, size.y)) - size + radius_tr;
67 	vec2 bottom_left = abs(relative_pos - vec2(size.x, 0)) - size + radius_bl;
68 	vec2 bottom_right = abs(relative_pos) - size + radius_br;
69 
70 	float dist = max(
71 		max(get_dist(top_left, radius_tl), get_dist(top_right, radius_tr)),
72 		max(get_dist(bottom_left, radius_bl), get_dist(bottom_right, radius_br))
73 	);
74 
75 	float result = smoothstep(0.0, 1.0, dist);
76 	return is_cutout ? result : 1.0 - result;
77 }
78 
79 float corner_dist(vec2 size, vec2 position,
80 		float radius_tl, float radius_tr, float radius_bl, float radius_br) {
81 	vec2 relative_pos = (gl_FragCoord.xy - position);
82 	relative_pos.y = size.y - relative_pos.y;
83 
84 	vec2 top_left = abs(relative_pos - size) - size + radius_tl;
85 	vec2 top_right = abs(relative_pos - vec2(0, size.y)) - size + radius_tr;
86 	vec2 bottom_left = abs(relative_pos - vec2(size.x, 0)) - size + radius_bl;
87 	vec2 bottom_right = abs(relative_pos) - size + radius_br;
88 
89 	float dist = max(
90 		max(get_dist(top_left, radius_tl), get_dist(top_right, radius_tr)),
91 		max(get_dist(bottom_left, radius_bl), get_dist(bottom_right, radius_br))
92 	);
93 
94 	return dist;
95 }