Skip transparent shadows in iced_tiny_skia
This commit is contained in:
parent
370b2f6df7
commit
4d502012b3
1 changed files with 103 additions and 96 deletions
|
|
@ -186,104 +186,91 @@ impl Backend {
|
|||
let path = rounded_rectangle(*bounds, fill_border_radius);
|
||||
|
||||
if let Some(shadow) = shadow {
|
||||
fn smoothstep(a: f32, b: f32, x: f32) -> f32 {
|
||||
let x = ((x - a) / (b - a)).clamp(0.0, 1.0);
|
||||
if shadow.color.a > 0.0 {
|
||||
let shadow_bounds = (Rectangle {
|
||||
x: bounds.x + shadow.offset.x - shadow.blur_radius,
|
||||
y: bounds.y + shadow.offset.y - shadow.blur_radius,
|
||||
width: bounds.width + shadow.blur_radius * 2.0,
|
||||
height: bounds.height + shadow.blur_radius * 2.0,
|
||||
} + translation)
|
||||
* scale_factor;
|
||||
|
||||
x * x * (3.0 - 2.0 * x)
|
||||
}
|
||||
|
||||
fn rounded_box_sdf(
|
||||
to_center: Vector,
|
||||
size: Size,
|
||||
radii: &[f32],
|
||||
) -> f32 {
|
||||
let radius =
|
||||
match (to_center.x > 0.0, to_center.y > 0.0) {
|
||||
(true, true) => radii[2],
|
||||
(true, false) => radii[1],
|
||||
(false, true) => radii[3],
|
||||
(false, false) => radii[0],
|
||||
};
|
||||
|
||||
let x = (to_center.x.abs() - size.width() + radius)
|
||||
.max(0.0);
|
||||
let y = (to_center.y.abs() - size.height() + radius)
|
||||
.max(0.0);
|
||||
|
||||
(x.powf(2.0) + y.powf(2.0)).sqrt() - radius
|
||||
}
|
||||
|
||||
let shadow_bounds = (Rectangle {
|
||||
x: bounds.x + shadow.offset.x - shadow.blur_radius,
|
||||
y: bounds.y + shadow.offset.y - shadow.blur_radius,
|
||||
width: bounds.width + shadow.blur_radius * 2.0,
|
||||
height: bounds.height + shadow.blur_radius * 2.0,
|
||||
} + translation)
|
||||
* scale_factor;
|
||||
|
||||
let radii = fill_border_radius
|
||||
.into_iter()
|
||||
.map(|radius| radius * scale_factor)
|
||||
.collect::<Vec<_>>();
|
||||
let (x, y, width, height) = (
|
||||
shadow_bounds.x as u32,
|
||||
shadow_bounds.y as u32,
|
||||
shadow_bounds.width as u32,
|
||||
shadow_bounds.height as u32,
|
||||
);
|
||||
let half_width = physical_bounds.width / 2.0;
|
||||
let half_height = physical_bounds.height / 2.0;
|
||||
|
||||
let colors = (y..y + height)
|
||||
.flat_map(|y| {
|
||||
(x..x + width).map(move |x| (x as f32, y as f32))
|
||||
})
|
||||
.filter_map(|(x, y)| {
|
||||
Size::from_wh(half_width, half_height).map(|size| {
|
||||
let shadow_distance = rounded_box_sdf(
|
||||
Vector::new(
|
||||
x - physical_bounds.position().x
|
||||
- (shadow.offset.x * scale_factor)
|
||||
- half_width,
|
||||
y - physical_bounds.position().y
|
||||
- (shadow.offset.y * scale_factor)
|
||||
- half_height,
|
||||
),
|
||||
size,
|
||||
&radii,
|
||||
);
|
||||
let shadow_alpha = 1.0
|
||||
- smoothstep(
|
||||
-shadow.blur_radius * scale_factor,
|
||||
shadow.blur_radius * scale_factor,
|
||||
shadow_distance,
|
||||
);
|
||||
|
||||
let mut color = into_color(shadow.color);
|
||||
color.apply_opacity(shadow_alpha);
|
||||
|
||||
color.to_color_u8().premultiply()
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
if let Some(pixmap) = tiny_skia::IntSize::from_wh(
|
||||
width, height,
|
||||
)
|
||||
.and_then(|size| {
|
||||
tiny_skia::Pixmap::from_vec(
|
||||
bytemuck::cast_vec(colors),
|
||||
size,
|
||||
)
|
||||
}) {
|
||||
pixels.draw_pixmap(
|
||||
x as i32,
|
||||
y as i32,
|
||||
pixmap.as_ref(),
|
||||
&tiny_skia::PixmapPaint::default(),
|
||||
tiny_skia::Transform::default(),
|
||||
None,
|
||||
let radii = fill_border_radius
|
||||
.into_iter()
|
||||
.map(|radius| radius * scale_factor)
|
||||
.collect::<Vec<_>>();
|
||||
let (x, y, width, height) = (
|
||||
shadow_bounds.x as u32,
|
||||
shadow_bounds.y as u32,
|
||||
shadow_bounds.width as u32,
|
||||
shadow_bounds.height as u32,
|
||||
);
|
||||
let half_width = physical_bounds.width / 2.0;
|
||||
let half_height = physical_bounds.height / 2.0;
|
||||
|
||||
let colors = (y..y + height)
|
||||
.flat_map(|y| {
|
||||
(x..x + width)
|
||||
.map(move |x| (x as f32, y as f32))
|
||||
})
|
||||
.filter_map(|(x, y)| {
|
||||
Size::from_wh(half_width, half_height).map(
|
||||
|size| {
|
||||
let shadow_distance = rounded_box_sdf(
|
||||
Vector::new(
|
||||
x - physical_bounds
|
||||
.position()
|
||||
.x
|
||||
- (shadow.offset.x
|
||||
* scale_factor)
|
||||
- half_width,
|
||||
y - physical_bounds
|
||||
.position()
|
||||
.y
|
||||
- (shadow.offset.y
|
||||
* scale_factor)
|
||||
- half_height,
|
||||
),
|
||||
size,
|
||||
&radii,
|
||||
);
|
||||
let shadow_alpha = 1.0
|
||||
- smoothstep(
|
||||
-shadow.blur_radius
|
||||
* scale_factor,
|
||||
shadow.blur_radius
|
||||
* scale_factor,
|
||||
shadow_distance,
|
||||
);
|
||||
|
||||
let mut color =
|
||||
into_color(shadow.color);
|
||||
color.apply_opacity(shadow_alpha);
|
||||
|
||||
color.to_color_u8().premultiply()
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
if let Some(pixmap) = tiny_skia::IntSize::from_wh(
|
||||
width, height,
|
||||
)
|
||||
.and_then(|size| {
|
||||
tiny_skia::Pixmap::from_vec(
|
||||
bytemuck::cast_vec(colors),
|
||||
size,
|
||||
)
|
||||
}) {
|
||||
pixels.draw_pixmap(
|
||||
x as i32,
|
||||
y as i32,
|
||||
pixmap.as_ref(),
|
||||
&tiny_skia::PixmapPaint::default(),
|
||||
tiny_skia::Transform::default(),
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -969,6 +956,26 @@ fn adjust_clip_mask(clip_mask: &mut tiny_skia::Mask, bounds: Rectangle) {
|
|||
);
|
||||
}
|
||||
|
||||
fn smoothstep(a: f32, b: f32, x: f32) -> f32 {
|
||||
let x = ((x - a) / (b - a)).clamp(0.0, 1.0);
|
||||
|
||||
x * x * (3.0 - 2.0 * x)
|
||||
}
|
||||
|
||||
fn rounded_box_sdf(to_center: Vector, size: Size, radii: &[f32]) -> f32 {
|
||||
let radius = match (to_center.x > 0.0, to_center.y > 0.0) {
|
||||
(true, true) => radii[2],
|
||||
(true, false) => radii[1],
|
||||
(false, true) => radii[3],
|
||||
(false, false) => radii[0],
|
||||
};
|
||||
|
||||
let x = (to_center.x.abs() - size.width() + radius).max(0.0);
|
||||
let y = (to_center.y.abs() - size.height() + radius).max(0.0);
|
||||
|
||||
(x.powf(2.0) + y.powf(2.0)).sqrt() - radius
|
||||
}
|
||||
|
||||
impl iced_graphics::Backend for Backend {
|
||||
type Primitive = primitive::Custom;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue