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

Better rounding of rectangles with thin outlines #5571

Merged
merged 4 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion crates/egui_kittest/src/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ pub enum SnapshotError {
}

const HOW_TO_UPDATE_SCREENSHOTS: &str =
"Run `UPDATE_SNAPSHOTS=1 cargo test` to update the snapshots.";
"Run `UPDATE_SNAPSHOTS=1 cargo test --all-features` to update the snapshots.";

impl Display for SnapshotError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Expand Down
54 changes: 17 additions & 37 deletions crates/epaint/src/tessellator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1291,29 +1291,6 @@ impl Tessellator {
self.clip_rect = clip_rect;
}

#[inline(always)]
pub fn round_to_pixel(&self, point: f32) -> f32 {
(point * self.pixels_per_point).round() / self.pixels_per_point
}

#[inline(always)]
pub fn round_to_pixel_center(&self, point: f32) -> f32 {
((point * self.pixels_per_point - 0.5).round() + 0.5) / self.pixels_per_point
}

#[inline(always)]
pub fn round_pos_to_pixel(&self, pos: Pos2) -> Pos2 {
pos2(self.round_to_pixel(pos.x), self.round_to_pixel(pos.y))
}

#[inline(always)]
pub fn round_pos_to_pixel_center(&self, pos: Pos2) -> Pos2 {
pos2(
self.round_to_pixel_center(pos.x),
self.round_to_pixel_center(pos.y),
)
}

/// Tessellate a clipped shape into a list of primitives.
pub fn tessellate_clipped_shape(
&mut self,
Expand Down Expand Up @@ -1716,8 +1693,16 @@ impl Tessellator {
// Since the stroke extends outside of the rectangle,
// we can round the rectangle sides to the physical pixel edges,
// and the filled rect will appear crisp, as will the inside of the stroke.
let Stroke { .. } = stroke; // Make sure we remember to update this if we change `stroke` to `PathStroke`
rect = rect.round_to_pixels(self.pixels_per_point);
let Stroke { width, .. } = stroke; // Make sure we remember to update this if we change `stroke` to `PathStroke`
if width <= self.feathering && !stroke.is_empty() {
// If the stroke is thin, make sure its center is in the center of the pixel:
rect = rect
.expand(width / 2.0)
.round_to_pixel_center(self.pixels_per_point)
.shrink(width / 2.0);
} else {
rect = rect.round_to_pixels(self.pixels_per_point);
}
}

// It is common to (sometimes accidentally) create an infinitely sized rectangle.
Expand All @@ -1727,7 +1712,7 @@ impl Tessellator {

let old_feathering = self.feathering;

if old_feathering < blur_width {
if self.feathering < blur_width {
// We accomplish the blur by using a larger-than-normal feathering.
// Feathering is usually used to make the edges of a shape softer for anti-aliasing.

Expand Down Expand Up @@ -1836,10 +1821,7 @@ impl Tessellator {
// The contents of the galley are already snapped to pixel coordinates,
// but we need to make sure the galley ends up on the start of a physical pixel:
let galley_pos = if self.options.round_text_to_pixels {
pos2(
self.round_to_pixel(galley_pos.x),
self.round_to_pixel(galley_pos.y),
)
galley_pos.round_to_pixels(self.pixels_per_point)
} else {
*galley_pos
};
Expand Down Expand Up @@ -1917,13 +1899,11 @@ impl Tessellator {
);

if *underline != Stroke::NONE {
self.scratchpad_path.clear();
self.scratchpad_path.add_line_segment([
self.round_pos_to_pixel_center(row_rect.left_bottom()),
self.round_pos_to_pixel_center(row_rect.right_bottom()),
]);
self.scratchpad_path
.stroke_open(0.0, &PathStroke::from(*underline), out);
self.tessellate_line_segment(
[row_rect.left_bottom(), row_rect.right_bottom()],
*underline,
out,
);
}
}
}
Expand Down
Loading