diff --git a/crates/gpui3/src/geometry.rs b/crates/gpui3/src/geometry.rs index 2616690b08..98ccfd58c3 100644 --- a/crates/gpui3/src/geometry.rs +++ b/crates/gpui3/src/geometry.rs @@ -276,6 +276,14 @@ impl + Sub> Bound && self.origin.y < their_lower_right.y && my_lower_right.y > other.origin.y } + + pub fn dilate(&mut self, amount: T) { + self.origin.x = self.origin.x.clone() - amount.clone(); + self.origin.y = self.origin.y.clone() - amount.clone(); + let double_amount = amount.clone() + amount; + self.size.width = self.size.width.clone() + double_amount.clone(); + self.size.height = self.size.height.clone() + double_amount; + } } impl + Sub> Bounds { diff --git a/crates/gpui3/src/platform/mac/shaders.metal b/crates/gpui3/src/platform/mac/shaders.metal index d079d2b808..580e46d2ab 100644 --- a/crates/gpui3/src/platform/mac/shaders.metal +++ b/crates/gpui3/src/platform/mac/shaders.metal @@ -13,7 +13,8 @@ float quad_sdf(float2 point, Bounds_ScaledPixels bounds, Corners_ScaledPixels corner_radii); float gaussian(float x, float sigma); float2 erf(float2 x); -float blur_along_x(float x, float y, float sigma, float corner, float2 half_size); +float blur_along_x(float x, float y, float sigma, float corner, + float2 half_size); struct QuadVertexOutput { float4 position [[position]]; @@ -32,9 +33,8 @@ vertex QuadVertexOutput quad_vertex(uint unit_vertex_id [[vertex_id]], [[buffer(QuadInputIndex_ViewportSize)]]) { float2 unit_vertex = unit_vertices[unit_vertex_id]; Quad quad = quads[quad_id]; - float4 device_position = to_device_position(unit_vertex, quad.bounds, - quad.content_mask.bounds, - viewport_size); + float4 device_position = to_device_position( + unit_vertex, quad.bounds, quad.content_mask.bounds, viewport_size); float4 background_color = hsla_to_rgba(quad.background); float4 border_color = hsla_to_rgba(quad.border_color); return QuadVertexOutput{device_position, background_color, border_color, @@ -120,82 +120,77 @@ struct ShadowVertexOutput { }; vertex ShadowVertexOutput shadow_vertex( - uint unit_vertex_id [[vertex_id]], - uint shadow_id [[instance_id]], + uint unit_vertex_id [[vertex_id]], uint shadow_id [[instance_id]], constant float2 *unit_vertices [[buffer(ShadowInputIndex_Vertices)]], constant Shadow *shadows [[buffer(ShadowInputIndex_Shadows)]], - constant Size_DevicePixels *viewport_size [[buffer(ShadowInputIndex_ViewportSize)]] -) { - float2 unit_vertex = unit_vertices[unit_vertex_id]; - Shadow shadow = shadows[shadow_id]; + constant Size_DevicePixels *viewport_size + [[buffer(ShadowInputIndex_ViewportSize)]]) { + float2 unit_vertex = unit_vertices[unit_vertex_id]; + Shadow shadow = shadows[shadow_id]; - float margin = (3. * shadow.blur_radius) + shadow.spread_radius; - // Set the bounds of the shadow and adjust its size based on the shadow's spread radius - // to achieve the spreading effect - Bounds_ScaledPixels bounds = shadow.bounds; - bounds.origin.x -= margin; - bounds.origin.y -= margin; - bounds.size.width += 2. * margin; - bounds.size.height += 2. * margin; + float margin = 3. * shadow.blur_radius; + // Set the bounds of the shadow and adjust its size based on the shadow's + // spread radius to achieve the spreading effect + Bounds_ScaledPixels bounds = shadow.bounds; + bounds.origin.x -= margin; + bounds.origin.y -= margin; + bounds.size.width += 2. * margin; + bounds.size.height += 2. * margin; - float4 device_position = to_device_position(unit_vertex, bounds, shadow.content_mask.bounds, viewport_size); - float4 color = hsla_to_rgba(shadow.color); + float4 device_position = to_device_position( + unit_vertex, bounds, shadow.content_mask.bounds, viewport_size); + float4 color = hsla_to_rgba(shadow.color); - return ShadowVertexOutput { - device_position, - color, - shadow_id, - }; + return ShadowVertexOutput{ + device_position, + color, + shadow_id, + }; } -fragment float4 shadow_fragment( - ShadowVertexOutput input [[stage_in]], - constant Shadow *shadows [[buffer(ShadowInputIndex_Shadows)]] -) { - Shadow shadow = shadows[input.shadow_id]; +fragment float4 shadow_fragment(ShadowVertexOutput input [[stage_in]], + constant Shadow *shadows + [[buffer(ShadowInputIndex_Shadows)]]) { + Shadow shadow = shadows[input.shadow_id]; - float2 origin = float2( - shadow.bounds.origin.x - shadow.spread_radius, - shadow.bounds.origin.y - shadow.spread_radius - ); - float2 size = float2( - shadow.bounds.size.width + shadow.spread_radius * 2., - shadow.bounds.size.height + shadow.spread_radius * 2. - ); - float2 half_size = size / 2.; - float2 center = origin + half_size; - float2 point = input.position.xy - center; - float corner_radius; - if (point.x < 0.) { - if (point.y < 0.) { - corner_radius = shadow.corner_radii.top_left; - } else { - corner_radius = shadow.corner_radii.bottom_left; - } + float2 origin = float2(shadow.bounds.origin.x, shadow.bounds.origin.y); + float2 size = float2(shadow.bounds.size.width, shadow.bounds.size.height); + float2 half_size = size / 2.; + float2 center = origin + half_size; + float2 point = input.position.xy - center; + float corner_radius; + if (point.x < 0.) { + if (point.y < 0.) { + corner_radius = shadow.corner_radii.top_left; } else { - if (point.y < 0.) { - corner_radius = shadow.corner_radii.top_right; - } else { - corner_radius = shadow.corner_radii.bottom_right; - } + corner_radius = shadow.corner_radii.bottom_left; } - - // The signal is only non-zero in a limited range, so don't waste samples - float low = point.y - half_size.y; - float high = point.y + half_size.y; - float start = clamp(-3. * shadow.blur_radius, low, high); - float end = clamp(3. * shadow.blur_radius, low, high); - - // Accumulate samples (we can get away with surprisingly few samples) - float step = (end - start) / 4.; - float y = start + step * 0.5; - float alpha = 0.; - for (int i = 0; i < 4; i++) { - alpha += blur_along_x(point.x, point.y - y, shadow.blur_radius, corner_radius, half_size) * gaussian(y, shadow.blur_radius) * step; - y += step; + } else { + if (point.y < 0.) { + corner_radius = shadow.corner_radii.top_right; + } else { + corner_radius = shadow.corner_radii.bottom_right; } + } - return input.color * float4(1., 1., 1., alpha); + // The signal is only non-zero in a limited range, so don't waste samples + float low = point.y - half_size.y; + float high = point.y + half_size.y; + float start = clamp(-3. * shadow.blur_radius, low, high); + float end = clamp(3. * shadow.blur_radius, low, high); + + // Accumulate samples (we can get away with surprisingly few samples) + float step = (end - start) / 4.; + float y = start + step * 0.5; + float alpha = 0.; + for (int i = 0; i < 4; i++) { + alpha += blur_along_x(point.x, point.y - y, shadow.blur_radius, + corner_radius, half_size) * + gaussian(y, shadow.blur_radius) * step; + y += step; + } + + return input.color * float4(1., 1., 1., alpha); } struct MonochromeSpriteVertexOutput { @@ -216,9 +211,10 @@ vertex MonochromeSpriteVertexOutput monochrome_sprite_vertex( float2 unit_vertex = unit_vertices[unit_vertex_id]; MonochromeSprite sprite = sprites[sprite_id]; - // Don't apply content mask at the vertex level because we don't have time to make sampling from the texture match the mask. - float4 device_position = to_device_position( - unit_vertex, sprite.bounds, sprite.bounds, viewport_size); + // Don't apply content mask at the vertex level because we don't have time to + // make sampling from the texture match the mask. + float4 device_position = to_device_position(unit_vertex, sprite.bounds, + sprite.bounds, viewport_size); float2 tile_position = to_tile_position(unit_vertex, sprite.tile, atlas_size); float4 color = hsla_to_rgba(sprite.color); return MonochromeSpriteVertexOutput{device_position, tile_position, color, @@ -234,11 +230,8 @@ fragment float4 monochrome_sprite_fragment( min_filter::linear); float4 sample = atlas_texture.sample(atlas_texture_sampler, input.tile_position); - float clip_distance = quad_sdf( - input.position.xy, - sprite.content_mask.bounds, - Corners_ScaledPixels { 0., 0., 0., 0. } - ); + float clip_distance = quad_sdf(input.position.xy, sprite.content_mask.bounds, + Corners_ScaledPixels{0., 0., 0., 0.}); float4 color = input.color; color.a *= sample.a * saturate(0.5 - clip_distance); return color; @@ -261,9 +254,10 @@ vertex PolychromeSpriteVertexOutput polychrome_sprite_vertex( float2 unit_vertex = unit_vertices[unit_vertex_id]; PolychromeSprite sprite = sprites[sprite_id]; - // Don't apply content mask at the vertex level because we don't have time to make sampling from the texture match the mask. - float4 device_position = to_device_position( - unit_vertex, sprite.bounds, sprite.bounds, viewport_size); + // Don't apply content mask at the vertex level because we don't have time to + // make sampling from the texture match the mask. + float4 device_position = to_device_position(unit_vertex, sprite.bounds, + sprite.bounds, viewport_size); float2 tile_position = to_tile_position(unit_vertex, sprite.tile, atlas_size); return PolychromeSpriteVertexOutput{device_position, tile_position, sprite_id}; @@ -278,8 +272,10 @@ fragment float4 polychrome_sprite_fragment( min_filter::linear); float4 sample = atlas_texture.sample(atlas_texture_sampler, input.tile_position); - float quad_distance = quad_sdf(input.position.xy, sprite.bounds, sprite.corner_radii); - float clip_distance = quad_sdf(input.position.xy, sprite.content_mask.bounds, Corners_ScaledPixels { 0., 0., 0., 0. }); + float quad_distance = + quad_sdf(input.position.xy, sprite.bounds, sprite.corner_radii); + float clip_distance = quad_sdf(input.position.xy, sprite.content_mask.bounds, + Corners_ScaledPixels{0., 0., 0., 0.}); float distance = max(quad_distance, clip_distance); float4 color = sample; @@ -399,21 +395,24 @@ float quad_sdf(float2 point, Bounds_ScaledPixels bounds, // A standard gaussian function, used for weighting samples float gaussian(float x, float sigma) { - return exp(-(x * x) / (2. * sigma * sigma)) / (sqrt(2. * M_PI_F) * sigma); + return exp(-(x * x) / (2. * sigma * sigma)) / (sqrt(2. * M_PI_F) * sigma); } // This approximates the error function, needed for the gaussian integral float2 erf(float2 x) { - float2 s = sign(x); - float2 a = abs(x); - x = 1. + (0.278393 + (0.230389 + 0.078108 * (a * a)) * a) * a; - x *= x; - return s - s / (x * x); + float2 s = sign(x); + float2 a = abs(x); + x = 1. + (0.278393 + (0.230389 + 0.078108 * (a * a)) * a) * a; + x *= x; + return s - s / (x * x); } -float blur_along_x(float x, float y, float sigma, float corner, float2 half_size) { - float delta = min(half_size.y - corner - abs(y), 0.); - float curved = half_size.x - corner + sqrt(max(0., corner * corner - delta * delta)); - float2 integral = 0.5 + 0.5 * erf((x + float2(-curved, curved)) * (sqrt(0.5) / sigma)); - return integral.y - integral.x; +float blur_along_x(float x, float y, float sigma, float corner, + float2 half_size) { + float delta = min(half_size.y - corner - abs(y), 0.); + float curved = + half_size.x - corner + sqrt(max(0., corner * corner - delta * delta)); + float2 integral = + 0.5 + 0.5 * erf((x + float2(-curved, curved)) * (sqrt(0.5) / sigma)); + return integral.y - integral.x; } diff --git a/crates/gpui3/src/scene.rs b/crates/gpui3/src/scene.rs index 6a897a78d2..0dad911383 100644 --- a/crates/gpui3/src/scene.rs +++ b/crates/gpui3/src/scene.rs @@ -261,7 +261,6 @@ pub struct Shadow { pub content_mask: ScaledContentMask, pub color: Hsla, pub blur_radius: ScaledPixels, - pub spread_radius: ScaledPixels, } impl Ord for Shadow { diff --git a/crates/gpui3/src/style.rs b/crates/gpui3/src/style.rs index 6ec12bbbd5..3caaaf491d 100644 --- a/crates/gpui3/src/style.rs +++ b/crates/gpui3/src/style.rs @@ -250,6 +250,7 @@ impl Style { let content_mask = cx.content_mask(); let mut shadow_bounds = bounds; shadow_bounds.origin += shadow.offset; + shadow_bounds.dilate(shadow.spread_radius); cx.scene().insert( layer_id, Shadow { @@ -258,11 +259,10 @@ impl Style { content_mask: content_mask.scale(scale), corner_radii: self .corner_radii - .to_pixels(bounds.size, rem_size) + .to_pixels(shadow_bounds.size, rem_size) .scale(scale), color: shadow.color, blur_radius: shadow.blur_radius.scale(scale), - spread_radius: shadow.spread_radius.scale(scale), }, ); } diff --git a/crates/storybook2/src/collab_panel.rs b/crates/storybook2/src/collab_panel.rs index 6f7602ace6..2d73b6f2ac 100644 --- a/crates/storybook2/src/collab_panel.rs +++ b/crates/storybook2/src/collab_panel.rs @@ -168,8 +168,8 @@ impl CollabPanel { .uri(avatar_uri) .size_3p5() .rounded_full() - .fill(theme.middle.positive.default.foreground) - .shadow_sm(), + // .fill(theme.middle.positive.default.foreground) + .shadow_md(), ) .child(label), )