diff --git a/crates/epaint/src/shadow.rs b/crates/epaint/src/shadow.rs index 71ce76c9..8b73c07e 100644 --- a/crates/epaint/src/shadow.rs +++ b/crates/epaint/src/shadow.rs @@ -1,3 +1,5 @@ +use emath::NumExt as _; + use super::*; /// The color and fuzziness of a fuzzy shape. @@ -16,7 +18,7 @@ pub struct Shadow { /// The width of the blur, i.e. the width of the fuzzy penumbra. /// - /// A value of 0.0 means no blur. + /// A value of 0.0 means a sharp shadow. pub blur: f32, /// Expand the shadow in all directions by this much. @@ -47,12 +49,26 @@ impl Shadow { color, } = *self; - let rect = rect.translate(offset); + let rect = rect.translate(offset).expand(spread); + + // We simulate a blurry shadow by tessellating a solid rectangle using a very large feathering. + // Feathering is usually used to make the edges of a shape softer for anti-aliasing. + // The tessellator can't handle blurring/feathering larger than the smallest side of the rect. + // Thats because the tessellator approximate very thin rectangles as line segments, + // and these line segments don't have rounded corners. + // When the feathering is small (the size of a pixel), this is usually fine, + // but here we have a huge feathering to simulate blur, + // so we need to avoid this optimization in the tessellator, + // which is also why we add this rather big epsilon: + let eps = 0.1; + let blur = blur.at_most(rect.size().min_elem() - eps).at_least(0.0); + + // TODO(emilk): if blur <= 0, return a simple `Shape::Rect` instead of using the tessellator let rounding_expansion = spread.abs() + 0.5 * blur; - let rounding = rounding.into() + Rounding::from(rounding_expansion); + let rounding = rounding.into() + Rounding::same(rounding_expansion); - let rect = RectShape::filled(rect.expand(spread), rounding, color); + let rect = RectShape::filled(rect, rounding, color); let pixels_per_point = 1.0; // doesn't matter here let font_tex_size = [1; 2]; // unused since we are not tessellating text. let mut tessellator = Tessellator::new(