@@ -159,6 +159,13 @@ pub struct Bounds<T: Clone + Debug> {
unsafe impl<T: Clone + Debug + Zeroable + Pod> Zeroable for Bounds<T> {}
unsafe impl<T: Clone + Debug + Zeroable + Pod> Pod for Bounds<T> {}
+impl<T: Clone + Debug + Mul<S, Output = T>, S: Clone> MulAssign<S> for Bounds<T> {
+ fn mul_assign(&mut self, rhs: S) {
+ self.origin *= rhs.clone();
+ self.size *= rhs;
+ }
+}
+
impl<T: Clone + Debug + Add<T, Output = T>> Bounds<T> {
pub fn upper_right(&self) -> Point<T> {
Point {
@@ -23,6 +23,11 @@ vertex QuadVertexOutput quad_vertex(
float2 unit_vertex = unit_vertices[unit_vertex_id];
Quad quad = quads[quad_id];
float2 position_2d = unit_vertex * float2(quad.bounds.size.width, quad.bounds.size.height) + float2(quad.bounds.origin.x, quad.bounds.origin.y);
+ position_2d.x = max(quad.clip_bounds.origin.x, position_2d.x);
+ position_2d.x = min(quad.clip_bounds.origin.x + quad.clip_bounds.size.width, position_2d.x);
+ position_2d.y = max(quad.clip_bounds.origin.y, position_2d.y);
+ position_2d.y = min(quad.clip_bounds.origin.y + quad.clip_bounds.size.height, position_2d.y);
+
float2 viewport_size = float2((float)uniforms->viewport_size.width, (float)uniforms->viewport_size.height);
float4 device_position = to_device_position(position_2d, viewport_size);
float4 background_color = hsla_to_rgba(quad.background);
@@ -35,13 +40,40 @@ vertex QuadVertexOutput quad_vertex(
};
}
+float quad_sdf(float2 point, Bounds_Pixels bounds, Corners_Pixels corner_radii) {
+ float2 half_size = float2(bounds.size.width, bounds.size.height) / 2.;
+ float2 center = float2(bounds.origin.x, bounds.origin.y) + half_size;
+ float2 center_to_point = point - center;
+ float corner_radius;
+ if (center_to_point.x < 0.) {
+ if (center_to_point.y < 0.) {
+ corner_radius = corner_radii.top_left;
+ } else {
+ corner_radius = corner_radii.bottom_left;
+ }
+ } else {
+ if (center_to_point.y < 0.) {
+ corner_radius = corner_radii.top_right;
+ } else {
+ corner_radius = corner_radii.bottom_right;
+ }
+ }
+
+ float2 rounded_edge_to_point = abs(center_to_point) - half_size + corner_radius;
+ float distance = length(max(0., rounded_edge_to_point))
+ + min(0., max(rounded_edge_to_point.x, rounded_edge_to_point.y))
+ - corner_radius;
+
+ return distance;
+}
+
fragment float4 quad_fragment(
QuadVertexOutput input [[stage_in]],
constant Quad *quads [[buffer(QuadInputIndex_Quads)]]
) {
Quad quad = quads[input.quad_id];
float2 half_size = float2(quad.bounds.size.width, quad.bounds.size.height) / 2.;
- float2 center = float2( quad.bounds.origin.x, quad.bounds.origin.y ) + half_size;
+ float2 center = float2(quad.bounds.origin.x, quad.bounds.origin.y) + half_size;
float2 center_to_point = input.position.xy - center;
float corner_radius;
if (center_to_point.x < 0.) {
@@ -91,7 +123,8 @@ fragment float4 quad_fragment(
color = float4(premultiplied_output_rgb, output_alpha);
}
- return color * float4(1., 1., 1., saturate(0.5 - distance));
+ float clip_distance = quad_sdf(input.position.xy, quad.clip_bounds, quad.clip_corner_radii);
+ return color * float4(1., 1., 1., saturate(0.5 - distance) * saturate(0.5 - clip_distance));
}
float4 hsla_to_rgba(Hsla hsla) {
@@ -1357,10 +1357,13 @@ extern "C" fn display_layer(this: &Object, _: Sel, _: id) {
size: size(100., 100.).map(px),
},
clip_bounds: Bounds {
- origin: point(10., 10.).map(px),
+ origin: point(20., 20.).map(px),
size: size(100., 100.).map(px),
},
- clip_corner_radii: Default::default(),
+ clip_corner_radii: crate::Corners {
+ top_left: px(10.),
+ ..Default::default()
+ },
background: crate::rgb(0x00ff00).into(),
border_color: Default::default(),
corner_radii: crate::Corners {
@@ -96,9 +96,8 @@ impl Quad {
}
pub fn scale(&mut self, factor: f32) {
- self.bounds.origin *= factor;
- self.bounds.size *= factor;
- self.clip_bounds.origin *= factor;
+ self.bounds *= factor;
+ self.clip_bounds *= factor;
self.clip_corner_radii *= factor;
self.corner_radii *= factor;
self.border_widths *= factor;