1
0
mirror of https://github.com/emilk/egui.git synced 2026-08-31 05:40:03 -04:00

Add epaint::Brush for controlling RectShape texturing (#5565)

Also wraps `Shape::Mesh` in an `Arc`.

No new features, but decreases size of `Shape` from 72 bytes to 64.
This commit is contained in:
Emil Ernerfeldt
2025-01-02 15:34:28 +01:00
committed by GitHub
parent 72ac2113dd
commit aeea70d9e7
7 changed files with 111 additions and 58 deletions

View File

@@ -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,18 +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?
/// Controls texturing, if any.
///
/// The texture is multiplied with [`Self::fill`].
pub fill_texture_id: TextureId,
/// Since most rectangles do not have a texture, this is optional and in an `Arc`,
/// so that [`RectShape`] is kept small..
pub brush: Option<Arc<Brush>>,
}
/// 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,
#[test]
fn rect_shape_size() {
assert_eq!(
std::mem::size_of::<RectShape>(), 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::<RectShape>() <= 64,
"RectShape is getting way too big!"
);
}
impl RectShape {
@@ -57,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(),
}
}
@@ -68,29 +74,14 @@ impl RectShape {
rounding: impl Into<Rounding>,
fill_color: impl Into<Color32>,
) -> 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<Rounding>, stroke: impl Into<Stroke>) -> 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
@@ -105,6 +96,16 @@ impl RectShape {
self
}
/// Set the texture to use when painting this rectangle, if any.
#[inline]
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 {
@@ -115,6 +116,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<RectShape> for Shape {

View File

@@ -56,7 +56,9 @@ pub enum Shape {
/// A general triangle mesh.
///
/// Can be used to display images.
Mesh(Mesh),
///
/// Wrapped in an [`Arc`] to minimize the size of [`Shape`].
Mesh(Arc<Mesh>),
/// A quadratic [Bézier Curve](https://en.wikipedia.org/wiki/B%C3%A9zier_curve).
QuadraticBezier(QuadraticBezierShape),
@@ -68,6 +70,18 @@ pub enum Shape {
Callback(PaintCallback),
}
#[test]
fn shape_size() {
assert_eq!(
std::mem::size_of::<Shape>(), 64,
"Shape 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::<Shape>() <= 64,
"Shape is getting way too big!"
);
}
#[test]
fn shape_impl_send_sync() {
fn assert_send_sync<T: Send + Sync>() {}
@@ -84,6 +98,13 @@ impl From<Vec<Self>> for Shape {
impl From<Mesh> for Shape {
#[inline(always)]
fn from(mesh: Mesh) -> Self {
Self::Mesh(mesh.into())
}
}
impl From<Arc<Mesh>> for Shape {
#[inline(always)]
fn from(mesh: Arc<Mesh>) -> Self {
Self::Mesh(mesh)
}
}
@@ -314,7 +335,8 @@ impl Shape {
}
#[inline]
pub fn mesh(mesh: Mesh) -> Self {
pub fn mesh(mesh: impl Into<Arc<Mesh>>) -> Self {
let mesh = mesh.into();
debug_assert!(mesh.is_valid());
Self::Mesh(mesh)
}
@@ -369,7 +391,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()
}
@@ -446,7 +468,7 @@ impl Shape {
galley.rect = transform.scaling * galley.rect;
}
Self::Mesh(mesh) => {
mesh.transform(transform);
Arc::make_mut(mesh).transform(transform);
}
Self::QuadraticBezier(bezier_shape) => {
bezier_shape.points[0] = transform * bezier_shape.points[0];