diff --git a/crates/egui/src/widgets/image.rs b/crates/egui/src/widgets/image.rs index 3abcf5fd5f0..d1976a12c45 100644 --- a/crates/egui/src/widgets/image.rs +++ b/crates/egui/src/widgets/image.rs @@ -9,7 +9,7 @@ use epaint::{ use crate::{ load::{Bytes, SizeHint, SizedTexture, TextureLoadResult, TexturePoll}, pos2, Color32, Context, Id, Mesh, Painter, Rect, Response, Rounding, Sense, Shape, Spinner, - Stroke, TextStyle, TextureOptions, Ui, Vec2, Widget, WidgetInfo, WidgetType, + TextStyle, TextureOptions, Ui, Vec2, Widget, WidgetInfo, WidgetType, }; /// A widget which displays an image. @@ -822,15 +822,10 @@ pub fn paint_texture_at( painter.add(Shape::mesh(mesh)); } None => { - painter.add(RectShape { - rect, - rounding: options.rounding, - fill: options.tint, - stroke: Stroke::NONE, - blur_width: 0.0, - fill_texture_id: texture.id, - uv: options.uv, - }); + painter.add( + RectShape::filled(rect, options.rounding, options.tint) + .with_texture(texture.id, options.uv), + ); } } } diff --git a/crates/epaint/src/brush.rs b/crates/epaint/src/brush.rs new file mode 100644 index 00000000000..a414194a15e --- /dev/null +++ b/crates/epaint/src/brush.rs @@ -0,0 +1,19 @@ +use crate::{Rect, TextureId}; + +/// Controls texturing of a [`crate::RectShape`]. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub struct Brush { + /// If the rect should be filled with a texture, which one? + /// + /// The texture is multiplied with [`crate::RectShape::fill`]. + pub fill_texture_id: TextureId, + + /// What UV coordinates to use for the texture? + /// + /// To display a texture, set [`Self::fill_texture_id`], + /// and set this to `Rect::from_min_max(pos2(0.0, 0.0), pos2(1.0, 1.0))`. + /// + /// Use [`Rect::ZERO`] to turn off texturing. + pub uv: Rect, +} diff --git a/crates/epaint/src/lib.rs b/crates/epaint/src/lib.rs index 5aeb96762d4..226821c16eb 100644 --- a/crates/epaint/src/lib.rs +++ b/crates/epaint/src/lib.rs @@ -23,6 +23,7 @@ #![allow(clippy::float_cmp)] #![allow(clippy::manual_range_contains)] +mod brush; pub mod color; pub mod image; mod margin; @@ -44,6 +45,7 @@ pub mod util; mod viewport; pub use self::{ + brush::Brush, color::ColorMode, image::{ColorImage, FontImage, ImageData, ImageDelta}, margin::Margin, diff --git a/crates/epaint/src/shape_transform.rs b/crates/epaint/src/shape_transform.rs index 263f9cf07a6..5ff087d926a 100644 --- a/crates/epaint/src/shape_transform.rs +++ b/crates/epaint/src/shape_transform.rs @@ -64,8 +64,7 @@ pub fn adjust_colors( fill, stroke, blur_width: _, - fill_texture_id: _, - uv: _, + brush: _, }) => { adjust_color(fill); adjust_color(&mut stroke.color); diff --git a/crates/epaint/src/shapes/rect_shape.rs b/crates/epaint/src/shapes/rect_shape.rs index 4780941e9a9..2c7f216a73e 100644 --- a/crates/epaint/src/shapes/rect_shape.rs +++ b/crates/epaint/src/shapes/rect_shape.rs @@ -1,7 +1,9 @@ +use std::sync::Arc; + use crate::*; /// How to paint a rectangle. -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct RectShape { pub rect: Rect, @@ -28,26 +30,23 @@ pub struct RectShape { /// The blur is currently implemented using a simple linear blur in sRGBA gamma space. pub blur_width: f32, - /// If the rect should be filled with a texture, which one? - /// - /// The texture is multiplied with [`Self::fill`]. - pub fill_texture_id: TextureId, - - /// What UV coordinates to use for the texture? + /// Controls texturing, if any. /// - /// To display a texture, set [`Self::fill_texture_id`], - /// and set this to `Rect::from_min_max(pos2(0.0, 0.0), pos2(1.0, 1.0))`. - /// - /// Use [`Rect::ZERO`] to turn off texturing. - pub uv: Rect, + /// Since most rectangles do not have a texture, this is optional and in an `Arc`, + /// so that [`RectShape`] is kept small.. + pub brush: Option>, } #[test] fn rect_shape_size() { assert_eq!( - std::mem::size_of::(), 72, + std::mem::size_of::(), 48, "RectShape changed size! If it shrank - good! Update this test. If it grew - bad! Try to find a way to avoid it." ); + assert!( + std::mem::size_of::() <= 64, + "RectShape is getting way too big!" + ); } impl RectShape { @@ -65,8 +64,7 @@ impl RectShape { fill: fill_color.into(), stroke: stroke.into(), blur_width: 0.0, - fill_texture_id: Default::default(), - uv: Rect::ZERO, + brush: Default::default(), } } @@ -76,29 +74,14 @@ impl RectShape { rounding: impl Into, fill_color: impl Into, ) -> Self { - Self { - rect, - rounding: rounding.into(), - fill: fill_color.into(), - stroke: Default::default(), - blur_width: 0.0, - fill_texture_id: Default::default(), - uv: Rect::ZERO, - } + Self::new(rect, rounding, fill_color, Stroke::NONE) } /// The stroke extends _outside_ the [`Rect`]. #[inline] pub fn stroke(rect: Rect, rounding: impl Into, stroke: impl Into) -> Self { - Self { - rect, - rounding: rounding.into(), - fill: Default::default(), - stroke: stroke.into(), - blur_width: 0.0, - fill_texture_id: Default::default(), - uv: Rect::ZERO, - } + let fill = Color32::TRANSPARENT; + Self::new(rect, rounding, fill, stroke) } /// If larger than zero, the edges of the rectangle @@ -113,6 +96,15 @@ impl RectShape { self } + /// Set the texture to use when painting this rectangle, if any. + pub fn with_texture(mut self, fill_texture_id: TextureId, uv: Rect) -> Self { + self.brush = Some(Arc::new(Brush { + fill_texture_id, + uv, + })); + self + } + /// The visual bounding rectangle (includes stroke width) #[inline] pub fn visual_bounding_rect(&self) -> Rect { @@ -123,6 +115,15 @@ impl RectShape { self.rect.expand(width + self.blur_width / 2.0) } } + + /// The texture to use when painting this rectangle, if any. + /// + /// If no texture is set, this will return [`TextureId::default`]. + pub fn fill_texture_id(&self) -> TextureId { + self.brush + .as_ref() + .map_or_else(TextureId::default, |brush| brush.fill_texture_id) + } } impl From for Shape { diff --git a/crates/epaint/src/shapes/shape.rs b/crates/epaint/src/shapes/shape.rs index 30654cc7418..93fff9e06d1 100644 --- a/crates/epaint/src/shapes/shape.rs +++ b/crates/epaint/src/shapes/shape.rs @@ -377,7 +377,7 @@ impl Shape { if let Self::Mesh(mesh) = self { mesh.texture_id } else if let Self::Rect(rect_shape) = self { - rect_shape.fill_texture_id + rect_shape.fill_texture_id() } else { crate::TextureId::default() } diff --git a/crates/epaint/src/tessellator.rs b/crates/epaint/src/tessellator.rs index 5e8b131cf71..8e5eb47dd40 100644 --- a/crates/epaint/src/tessellator.rs +++ b/crates/epaint/src/tessellator.rs @@ -1693,14 +1693,14 @@ impl Tessellator { /// * `rect`: the rectangle to tessellate. /// * `out`: triangles are appended to this. pub fn tessellate_rect(&mut self, rect: &RectShape, out: &mut Mesh) { + let brush = rect.brush.as_ref(); let RectShape { mut rect, mut rounding, fill, stroke, mut blur_width, - fill_texture_id, - uv, + .. } = *rect; if self.options.coarse_tessellation_culling @@ -1775,7 +1775,11 @@ impl Tessellator { path.add_line_loop(&self.scratchpad_points); let path_stroke = PathStroke::from(stroke).outside(); - if uv.is_positive() { + if let Some(brush) = brush { + let crate::Brush { + fill_texture_id, + uv, + } = **brush; // Textured let uv_from_pos = |p: Pos2| { pos2(