Checkpoint!
This commit is contained in:
parent
657a25178d
commit
fe3ef08f39
5 changed files with 103 additions and 97 deletions
|
@ -276,6 +276,14 @@ impl<T: Clone + Debug + PartialOrd + Add<T, Output = T> + Sub<Output = T>> Bound
|
||||||
&& self.origin.y < their_lower_right.y
|
&& self.origin.y < their_lower_right.y
|
||||||
&& my_lower_right.y > other.origin.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<T: Clone + Debug + PartialOrd + Add<T, Output = T> + Sub<Output = T>> Bounds<T> {
|
impl<T: Clone + Debug + PartialOrd + Add<T, Output = T> + Sub<Output = T>> Bounds<T> {
|
||||||
|
|
|
@ -13,7 +13,8 @@ float quad_sdf(float2 point, Bounds_ScaledPixels bounds,
|
||||||
Corners_ScaledPixels corner_radii);
|
Corners_ScaledPixels corner_radii);
|
||||||
float gaussian(float x, float sigma);
|
float gaussian(float x, float sigma);
|
||||||
float2 erf(float2 x);
|
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 {
|
struct QuadVertexOutput {
|
||||||
float4 position [[position]];
|
float4 position [[position]];
|
||||||
|
@ -32,9 +33,8 @@ vertex QuadVertexOutput quad_vertex(uint unit_vertex_id [[vertex_id]],
|
||||||
[[buffer(QuadInputIndex_ViewportSize)]]) {
|
[[buffer(QuadInputIndex_ViewportSize)]]) {
|
||||||
float2 unit_vertex = unit_vertices[unit_vertex_id];
|
float2 unit_vertex = unit_vertices[unit_vertex_id];
|
||||||
Quad quad = quads[quad_id];
|
Quad quad = quads[quad_id];
|
||||||
float4 device_position = to_device_position(unit_vertex, quad.bounds,
|
float4 device_position = to_device_position(
|
||||||
quad.content_mask.bounds,
|
unit_vertex, quad.bounds, quad.content_mask.bounds, viewport_size);
|
||||||
viewport_size);
|
|
||||||
float4 background_color = hsla_to_rgba(quad.background);
|
float4 background_color = hsla_to_rgba(quad.background);
|
||||||
float4 border_color = hsla_to_rgba(quad.border_color);
|
float4 border_color = hsla_to_rgba(quad.border_color);
|
||||||
return QuadVertexOutput{device_position, background_color, border_color,
|
return QuadVertexOutput{device_position, background_color, border_color,
|
||||||
|
@ -120,82 +120,77 @@ struct ShadowVertexOutput {
|
||||||
};
|
};
|
||||||
|
|
||||||
vertex ShadowVertexOutput shadow_vertex(
|
vertex ShadowVertexOutput shadow_vertex(
|
||||||
uint unit_vertex_id [[vertex_id]],
|
uint unit_vertex_id [[vertex_id]], uint shadow_id [[instance_id]],
|
||||||
uint shadow_id [[instance_id]],
|
|
||||||
constant float2 *unit_vertices [[buffer(ShadowInputIndex_Vertices)]],
|
constant float2 *unit_vertices [[buffer(ShadowInputIndex_Vertices)]],
|
||||||
constant Shadow *shadows [[buffer(ShadowInputIndex_Shadows)]],
|
constant Shadow *shadows [[buffer(ShadowInputIndex_Shadows)]],
|
||||||
constant Size_DevicePixels *viewport_size [[buffer(ShadowInputIndex_ViewportSize)]]
|
constant Size_DevicePixels *viewport_size
|
||||||
) {
|
[[buffer(ShadowInputIndex_ViewportSize)]]) {
|
||||||
float2 unit_vertex = unit_vertices[unit_vertex_id];
|
float2 unit_vertex = unit_vertices[unit_vertex_id];
|
||||||
Shadow shadow = shadows[shadow_id];
|
Shadow shadow = shadows[shadow_id];
|
||||||
|
|
||||||
float margin = (3. * shadow.blur_radius) + shadow.spread_radius;
|
float margin = 3. * shadow.blur_radius;
|
||||||
// Set the bounds of the shadow and adjust its size based on the shadow's spread radius
|
// Set the bounds of the shadow and adjust its size based on the shadow's
|
||||||
// to achieve the spreading effect
|
// spread radius to achieve the spreading effect
|
||||||
Bounds_ScaledPixels bounds = shadow.bounds;
|
Bounds_ScaledPixels bounds = shadow.bounds;
|
||||||
bounds.origin.x -= margin;
|
bounds.origin.x -= margin;
|
||||||
bounds.origin.y -= margin;
|
bounds.origin.y -= margin;
|
||||||
bounds.size.width += 2. * margin;
|
bounds.size.width += 2. * margin;
|
||||||
bounds.size.height += 2. * margin;
|
bounds.size.height += 2. * margin;
|
||||||
|
|
||||||
float4 device_position = to_device_position(unit_vertex, bounds, shadow.content_mask.bounds, viewport_size);
|
float4 device_position = to_device_position(
|
||||||
float4 color = hsla_to_rgba(shadow.color);
|
unit_vertex, bounds, shadow.content_mask.bounds, viewport_size);
|
||||||
|
float4 color = hsla_to_rgba(shadow.color);
|
||||||
|
|
||||||
return ShadowVertexOutput {
|
return ShadowVertexOutput{
|
||||||
device_position,
|
device_position,
|
||||||
color,
|
color,
|
||||||
shadow_id,
|
shadow_id,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fragment float4 shadow_fragment(
|
fragment float4 shadow_fragment(ShadowVertexOutput input [[stage_in]],
|
||||||
ShadowVertexOutput input [[stage_in]],
|
constant Shadow *shadows
|
||||||
constant Shadow *shadows [[buffer(ShadowInputIndex_Shadows)]]
|
[[buffer(ShadowInputIndex_Shadows)]]) {
|
||||||
) {
|
Shadow shadow = shadows[input.shadow_id];
|
||||||
Shadow shadow = shadows[input.shadow_id];
|
|
||||||
|
|
||||||
float2 origin = float2(
|
float2 origin = float2(shadow.bounds.origin.x, shadow.bounds.origin.y);
|
||||||
shadow.bounds.origin.x - shadow.spread_radius,
|
float2 size = float2(shadow.bounds.size.width, shadow.bounds.size.height);
|
||||||
shadow.bounds.origin.y - shadow.spread_radius
|
float2 half_size = size / 2.;
|
||||||
);
|
float2 center = origin + half_size;
|
||||||
float2 size = float2(
|
float2 point = input.position.xy - center;
|
||||||
shadow.bounds.size.width + shadow.spread_radius * 2.,
|
float corner_radius;
|
||||||
shadow.bounds.size.height + shadow.spread_radius * 2.
|
if (point.x < 0.) {
|
||||||
);
|
if (point.y < 0.) {
|
||||||
float2 half_size = size / 2.;
|
corner_radius = shadow.corner_radii.top_left;
|
||||||
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;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (point.y < 0.) {
|
corner_radius = shadow.corner_radii.bottom_left;
|
||||||
corner_radius = shadow.corner_radii.top_right;
|
|
||||||
} else {
|
|
||||||
corner_radius = shadow.corner_radii.bottom_right;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
// The signal is only non-zero in a limited range, so don't waste samples
|
if (point.y < 0.) {
|
||||||
float low = point.y - half_size.y;
|
corner_radius = shadow.corner_radii.top_right;
|
||||||
float high = point.y + half_size.y;
|
} else {
|
||||||
float start = clamp(-3. * shadow.blur_radius, low, high);
|
corner_radius = shadow.corner_radii.bottom_right;
|
||||||
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);
|
// 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 {
|
struct MonochromeSpriteVertexOutput {
|
||||||
|
@ -216,9 +211,10 @@ vertex MonochromeSpriteVertexOutput monochrome_sprite_vertex(
|
||||||
|
|
||||||
float2 unit_vertex = unit_vertices[unit_vertex_id];
|
float2 unit_vertex = unit_vertices[unit_vertex_id];
|
||||||
MonochromeSprite sprite = sprites[sprite_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.
|
// Don't apply content mask at the vertex level because we don't have time to
|
||||||
float4 device_position = to_device_position(
|
// make sampling from the texture match the mask.
|
||||||
unit_vertex, sprite.bounds, sprite.bounds, viewport_size);
|
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);
|
float2 tile_position = to_tile_position(unit_vertex, sprite.tile, atlas_size);
|
||||||
float4 color = hsla_to_rgba(sprite.color);
|
float4 color = hsla_to_rgba(sprite.color);
|
||||||
return MonochromeSpriteVertexOutput{device_position, tile_position, color,
|
return MonochromeSpriteVertexOutput{device_position, tile_position, color,
|
||||||
|
@ -234,11 +230,8 @@ fragment float4 monochrome_sprite_fragment(
|
||||||
min_filter::linear);
|
min_filter::linear);
|
||||||
float4 sample =
|
float4 sample =
|
||||||
atlas_texture.sample(atlas_texture_sampler, input.tile_position);
|
atlas_texture.sample(atlas_texture_sampler, input.tile_position);
|
||||||
float clip_distance = quad_sdf(
|
float clip_distance = quad_sdf(input.position.xy, sprite.content_mask.bounds,
|
||||||
input.position.xy,
|
Corners_ScaledPixels{0., 0., 0., 0.});
|
||||||
sprite.content_mask.bounds,
|
|
||||||
Corners_ScaledPixels { 0., 0., 0., 0. }
|
|
||||||
);
|
|
||||||
float4 color = input.color;
|
float4 color = input.color;
|
||||||
color.a *= sample.a * saturate(0.5 - clip_distance);
|
color.a *= sample.a * saturate(0.5 - clip_distance);
|
||||||
return color;
|
return color;
|
||||||
|
@ -261,9 +254,10 @@ vertex PolychromeSpriteVertexOutput polychrome_sprite_vertex(
|
||||||
|
|
||||||
float2 unit_vertex = unit_vertices[unit_vertex_id];
|
float2 unit_vertex = unit_vertices[unit_vertex_id];
|
||||||
PolychromeSprite sprite = sprites[sprite_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.
|
// Don't apply content mask at the vertex level because we don't have time to
|
||||||
float4 device_position = to_device_position(
|
// make sampling from the texture match the mask.
|
||||||
unit_vertex, sprite.bounds, sprite.bounds, viewport_size);
|
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);
|
float2 tile_position = to_tile_position(unit_vertex, sprite.tile, atlas_size);
|
||||||
return PolychromeSpriteVertexOutput{device_position, tile_position,
|
return PolychromeSpriteVertexOutput{device_position, tile_position,
|
||||||
sprite_id};
|
sprite_id};
|
||||||
|
@ -278,8 +272,10 @@ fragment float4 polychrome_sprite_fragment(
|
||||||
min_filter::linear);
|
min_filter::linear);
|
||||||
float4 sample =
|
float4 sample =
|
||||||
atlas_texture.sample(atlas_texture_sampler, input.tile_position);
|
atlas_texture.sample(atlas_texture_sampler, input.tile_position);
|
||||||
float quad_distance = quad_sdf(input.position.xy, sprite.bounds, sprite.corner_radii);
|
float quad_distance =
|
||||||
float clip_distance = quad_sdf(input.position.xy, sprite.content_mask.bounds, Corners_ScaledPixels { 0., 0., 0., 0. });
|
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);
|
float distance = max(quad_distance, clip_distance);
|
||||||
|
|
||||||
float4 color = sample;
|
float4 color = sample;
|
||||||
|
@ -399,21 +395,24 @@ float quad_sdf(float2 point, Bounds_ScaledPixels bounds,
|
||||||
|
|
||||||
// A standard gaussian function, used for weighting samples
|
// A standard gaussian function, used for weighting samples
|
||||||
float gaussian(float x, float sigma) {
|
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
|
// This approximates the error function, needed for the gaussian integral
|
||||||
float2 erf(float2 x) {
|
float2 erf(float2 x) {
|
||||||
float2 s = sign(x);
|
float2 s = sign(x);
|
||||||
float2 a = abs(x);
|
float2 a = abs(x);
|
||||||
x = 1. + (0.278393 + (0.230389 + 0.078108 * (a * a)) * a) * a;
|
x = 1. + (0.278393 + (0.230389 + 0.078108 * (a * a)) * a) * a;
|
||||||
x *= x;
|
x *= x;
|
||||||
return s - s / (x * x);
|
return s - s / (x * 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,
|
||||||
float delta = min(half_size.y - corner - abs(y), 0.);
|
float2 half_size) {
|
||||||
float curved = half_size.x - corner + sqrt(max(0., corner * corner - delta * delta));
|
float delta = min(half_size.y - corner - abs(y), 0.);
|
||||||
float2 integral = 0.5 + 0.5 * erf((x + float2(-curved, curved)) * (sqrt(0.5) / sigma));
|
float curved =
|
||||||
return integral.y - integral.x;
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -261,7 +261,6 @@ pub struct Shadow {
|
||||||
pub content_mask: ScaledContentMask,
|
pub content_mask: ScaledContentMask,
|
||||||
pub color: Hsla,
|
pub color: Hsla,
|
||||||
pub blur_radius: ScaledPixels,
|
pub blur_radius: ScaledPixels,
|
||||||
pub spread_radius: ScaledPixels,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ord for Shadow {
|
impl Ord for Shadow {
|
||||||
|
|
|
@ -250,6 +250,7 @@ impl Style {
|
||||||
let content_mask = cx.content_mask();
|
let content_mask = cx.content_mask();
|
||||||
let mut shadow_bounds = bounds;
|
let mut shadow_bounds = bounds;
|
||||||
shadow_bounds.origin += shadow.offset;
|
shadow_bounds.origin += shadow.offset;
|
||||||
|
shadow_bounds.dilate(shadow.spread_radius);
|
||||||
cx.scene().insert(
|
cx.scene().insert(
|
||||||
layer_id,
|
layer_id,
|
||||||
Shadow {
|
Shadow {
|
||||||
|
@ -258,11 +259,10 @@ impl Style {
|
||||||
content_mask: content_mask.scale(scale),
|
content_mask: content_mask.scale(scale),
|
||||||
corner_radii: self
|
corner_radii: self
|
||||||
.corner_radii
|
.corner_radii
|
||||||
.to_pixels(bounds.size, rem_size)
|
.to_pixels(shadow_bounds.size, rem_size)
|
||||||
.scale(scale),
|
.scale(scale),
|
||||||
color: shadow.color,
|
color: shadow.color,
|
||||||
blur_radius: shadow.blur_radius.scale(scale),
|
blur_radius: shadow.blur_radius.scale(scale),
|
||||||
spread_radius: shadow.spread_radius.scale(scale),
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,8 +168,8 @@ impl CollabPanel {
|
||||||
.uri(avatar_uri)
|
.uri(avatar_uri)
|
||||||
.size_3p5()
|
.size_3p5()
|
||||||
.rounded_full()
|
.rounded_full()
|
||||||
.fill(theme.middle.positive.default.foreground)
|
// .fill(theme.middle.positive.default.foreground)
|
||||||
.shadow_sm(),
|
.shadow_md(),
|
||||||
)
|
)
|
||||||
.child(label),
|
.child(label),
|
||||||
)
|
)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue