Match shell squircle outlines with compositor masks

Use shared corner geometry for shell controls, window clipping, materials and blur masks. Preserve circular pills and controls where appropriate, track contour changes in damage, and use tagged ferese-shape and libcosmic dependencies.
This commit is contained in:
Samuel Onoja authored and GitHub committed 2026-10-04 07:39:54 +01:00
1 parent 03a265b97f
commit d75c93db85
31 files changed
+453 -80

No files matched your search

@@ -15,6 +15,9 @@ void main() {
float sdf = rounded_rect_distance(gl_FragCoord.xy, visible_rect, material_radius);
float coverage = edge_coverage(sdf);
if (paint_mode > 0.5) {
// The shadow pass is multiplied by (1 - coverage). Fully covered
// pixels need neither a second contour solve nor a Gaussian sample.
if (coverage >= 1.0) { gl_FragColor = vec4(0.0); return; }
float distance = max(rounded_rect_distance(gl_FragCoord.xy, shadow_rect, material_radius), 0.0);
float sigma = max(shadow_values.x * 0.5, 0.5);
float opacity = exp(-0.5 * distance * distance / (sigma * sigma))
@@ -26,7 +26,7 @@ void main() {
#ifdef CONTINUOUS_WINDOW_CORNERS
// Inset the outer distance field along its normals, rather than shrinking
// the quartic's bounding box/radius and changing border thickness.
// the profile's bounding box/radius and changing border thickness.
float inner_coverage = edge_coverage(signed_distance + border_width);
#else
vec2 inner_size = max(clip_rect.zw - vec2(2.0 * border_width), vec2(0.0));
@@ -44,7 +44,11 @@ float corner_nearest(vec2 query, float t, vec2 a, vec2 b, vec2 c, vec2 d) {
vec2 error = point - query;
float speed_squared = dot(tangent, tangent);
float denominator = max(speed_squared + dot(error, acceleration), speed_squared * 0.25);
t = clamp(t - clamp(dot(error, tangent) / denominator, -0.25, 0.25), 0.0, 1.0);
float next = clamp(t - clamp(dot(error, tangent) / denominator, -0.25, 0.25), 0.0, 1.0);
if (next == t) {
break;
}
t = next;
}
return t;
@@ -71,13 +75,23 @@ float rounded_rect_distance(vec2 point, vec4 rect, float radius) {
return -min(inset.x, inset.y);
}
vec2 query = inset / radius;
// Reflect onto the first half of the symmetric corner. The opposite
// shoulder cannot be nearer than its reflection, so omit segment 2.
vec2 query = vec2(min(inset.x, inset.y), max(inset.x, inset.y)) / radius;
float best_squared = 1.0e20;
float side = 1.0;
for (int segment = 0; segment < 3; segment++) {
for (int segment = 0; segment < 2; segment++) {
vec2 a, b, c, d;
corner_controls(segment, blend, a, b, c, d);
// The cubic stays inside its control hull. Reject only when even
// that hull's box cannot improve the closest point found so far.
vec2 low = min(min(a, b), min(c, d));
vec2 high = max(max(a, b), max(c, d));
vec2 delta = max(max(low - query, query - high), 0.0);
if (dot(delta, delta) > best_squared) {
continue;
}
for (int seed = 0; seed < 2; seed++) {
float t = corner_nearest(query, float(seed), a, b, c, d);