Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve tessellation quality #5669

Merged
merged 41 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
e98d357
Add a manual Tessellation Test
emilk Feb 2, 2025
f316545
Add Color32::PURPLE
emilk Feb 2, 2025
64c757c
Stop using `for_each`
emilk Feb 2, 2025
ae670d5
Rename: call it `uv_bbox` for clarity
emilk Feb 2, 2025
78a21c2
Clarify how the opacity change for thin lines work
emilk Feb 2, 2025
1b9c9d8
Better wording: "middle color"
emilk Feb 2, 2025
f5152c4
More sensitive DragValue for feathering
emilk Feb 2, 2025
385b2f8
flip `>` -> `<`
emilk Feb 2, 2025
4dba1f4
inner -> middle
emilk Feb 2, 2025
c61f11b
Stroke and fill paths in one go
emilk Feb 2, 2025
1d2d51b
better tessellation test
emilk Feb 2, 2025
1d70292
Rounding: use saturating addition
emilk Feb 2, 2025
f58b87d
Add `PathStroke::with_kind`
emilk Feb 2, 2025
66eca93
Better handling of rounding
emilk Feb 3, 2025
4990b2e
Better handling of thin strokes
emilk Feb 3, 2025
edb522e
Better handling of thin rectangles
emilk Feb 3, 2025
92ec06d
Add `Color32::blend`
emilk Feb 3, 2025
e490c6b
Don't loose the last piece of rounding
emilk Feb 3, 2025
1aa57f9
Make some prefabs for the test
emilk Feb 3, 2025
90da19a
Document limitation with blur_width
emilk Feb 3, 2025
05bcd18
Better handling of rounding
emilk Feb 3, 2025
501292c
Tweak
emilk Feb 3, 2025
c5f293c
Bug fix: scale rectangle blur when transforming a RectShape
emilk Feb 3, 2025
eec343b
Use `Roundingf`
emilk Feb 3, 2025
07a7df7
Define rounding/corner_radius properly
emilk Feb 3, 2025
d3f0985
Revert rounding cutoffs
emilk Feb 3, 2025
e62db7c
Tweak rounding
emilk Feb 3, 2025
42857c6
Fix dark patch in top corners of windows
emilk Feb 3, 2025
00d0857
Update snapshot tests
emilk Feb 3, 2025
e0657a0
Fix docstring
emilk Feb 4, 2025
c773d57
Better comment
emilk Feb 4, 2025
6b8eab7
Add comment
emilk Feb 4, 2025
fa5a45d
No blending
emilk Feb 4, 2025
2ef1d32
Merge branch 'master' into emilk/improve-tessellator
emilk Feb 4, 2025
7c81106
Add option to paint the edges of the triangles
emilk Feb 4, 2025
e137e28
Add test for blur with stroke
emilk Feb 4, 2025
6f33639
Kittest: create relative folders, if needed
emilk Feb 4, 2025
7691d50
Add screenshot tests
emilk Feb 4, 2025
68c9d36
Apply blur earlier to fix some artifacts
emilk Feb 4, 2025
6a00a7d
Explain why we can't resuse vertices
emilk Feb 4, 2025
9eac062
Remove erroneous early-out
emilk Feb 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions crates/ecolor/src/color32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ impl Color32 {
pub const BLUE: Self = Self::from_rgb(0, 0, 255);
pub const LIGHT_BLUE: Self = Self::from_rgb(0xAD, 0xD8, 0xE6);

pub const PURPLE: Self = Self::from_rgb(0x80, 0, 0x80);

pub const GOLD: Self = Self::from_rgb(255, 215, 0);

pub const DEBUG_COLOR: Self = Self::from_rgba_premultiplied(0, 200, 0, 128);
Expand Down Expand Up @@ -233,6 +235,23 @@ impl Color32 {
])
}

/// Multiply with 127 to make color half as opaque, perceptually.
///
/// Fast multiplication in gamma-space.
///
/// This is perceptually even, and faster that [`Self::linear_multiply`].
#[inline]
pub fn gamma_multiply_u8(self, factor: u8) -> Self {
let Self([r, g, b, a]) = self;
let factor = factor as u32;
Self([
((r as u32 * factor + 127) / 255) as u8,
((g as u32 * factor + 127) / 255) as u8,
((b as u32 * factor + 127) / 255) as u8,
((a as u32 * factor + 127) / 255) as u8,
])
}

/// Multiply with 0.5 to make color half as opaque in linear space.
///
/// This is using linear space, which is not perceptually even.
Expand Down Expand Up @@ -271,6 +290,11 @@ impl Color32 {
fast_round(lerp((self[3] as f32)..=(other[3] as f32), t)),
)
}

/// Blend two colors, so that `self` is behind the argument.
pub fn blend(self, on_top: Self) -> Self {
self.gamma_multiply_u8(255 - on_top.a()) + on_top
}
}

impl std::ops::Mul for Color32 {
Expand All @@ -287,3 +311,17 @@ impl std::ops::Mul for Color32 {
])
}
}

impl std::ops::Add for Color32 {
type Output = Self;

#[inline]
fn add(self, other: Self) -> Self {
Self([
self[0].saturating_add(other[0]),
self[1].saturating_add(other[1]),
self[2].saturating_add(other[2]),
self[3].saturating_add(other[3]),
])
}
}
15 changes: 10 additions & 5 deletions crates/egui/src/containers/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,10 @@ pub struct Frame {
#[doc(alias = "border")]
pub stroke: Stroke,

/// The rounding of the corners of [`Self::stroke`] and [`Self::fill`].
/// The rounding of the _outer_ corner of the [`Self::stroke`]
/// (or, if there is no stroke, the outer corner of [`Self::fill`]).
///
/// In other words, this is the corner radius of the _widget rect_.
pub rounding: Rounding,

/// Margin outside the painted frame.
Expand Down Expand Up @@ -269,7 +272,10 @@ impl Frame {
self
}

/// The rounding of the corners of [`Self::stroke`] and [`Self::fill`].
/// The rounding of the _outer_ corner of the [`Self::stroke`]
/// (or, if there is no stroke, the outer corner of [`Self::fill`]).
///
/// In other words, this is the corner radius of the _widget rect_.
#[inline]
pub fn rounding(mut self, rounding: impl Into<Rounding>) -> Self {
self.rounding = rounding.into();
Expand Down Expand Up @@ -423,15 +429,14 @@ impl Frame {
shadow,
} = *self;

let fill_rect = self.fill_rect(content_rect);
let widget_rect = self.widget_rect(content_rect);

let frame_shape = Shape::Rect(epaint::RectShape::new(
fill_rect,
widget_rect,
rounding,
fill,
stroke,
epaint::StrokeKind::Outside,
epaint::StrokeKind::Inside,
));

if shadow == Default::default() {
Expand Down
3 changes: 2 additions & 1 deletion crates/egui/src/containers/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,8 @@ impl Window<'_> {
title_bar.inner_rect.round_to_pixels(ctx.pixels_per_point());

if on_top && area_content_ui.visuals().window_highlight_topmost {
let mut round = window_frame.rounding;
let mut round =
window_frame.rounding - window_frame.stroke.width.round() as u8;
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe rename rounding to corner_radius everywhere?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's do it in a follow-up PR


if !is_collapsed {
round.se = 0;
Expand Down
2 changes: 1 addition & 1 deletion crates/egui/src/introspection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ impl Widget for &mut epaint::TessellationOptions {
.on_hover_text("Apply feathering to smooth out the edges of shapes. Turn off for small performance gain.");

if *feathering {
ui.add(crate::DragValue::new(feathering_size_in_pixels).range(0.0..=10.0).speed(0.1).suffix(" px"));
ui.add(crate::DragValue::new(feathering_size_in_pixels).range(0.0..=10.0).speed(0.025).suffix(" px"));
}
});

Expand Down
4 changes: 2 additions & 2 deletions crates/egui_demo_app/tests/snapshots/imageviewer.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions crates/egui_demo_lib/src/demo/demo_app_windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ impl Default for DemoGroups {
Box::<super::tests::InputTest>::default(),
Box::<super::tests::LayoutTest>::default(),
Box::<super::tests::ManualLayoutTest>::default(),
Box::<super::tests::TessellationTest>::default(),
Box::<super::tests::WindowResizeTest>::default(),
]),
}
Expand Down
6 changes: 3 additions & 3 deletions crates/egui_demo_lib/src/demo/misc_demo_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,9 @@ impl View for MiscDemoWindow {
)
.changed()
{
self.checklist
.iter_mut()
.for_each(|checked| *checked = all_checked);
for check in &mut self.checklist {
*check = all_checked;
}
}
for (i, checked) in self.checklist.iter_mut().enumerate() {
ui.checkbox(checked, format!("Item {}", i + 1));
Expand Down
2 changes: 2 additions & 0 deletions crates/egui_demo_lib/src/demo/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod input_event_history;
mod input_test;
mod layout_test;
mod manual_layout_test;
mod tessellation_test;
mod window_resize_test;

pub use clipboard_test::ClipboardTest;
Expand All @@ -16,4 +17,5 @@ pub use input_event_history::InputEventHistory;
pub use input_test::InputTest;
pub use layout_test::LayoutTest;
pub use manual_layout_test::ManualLayoutTest;
pub use tessellation_test::TessellationTest;
pub use window_resize_test::WindowResizeTest;
Loading