From 84aa8df05ab26b41283e1192791764d545cf34a2 Mon Sep 17 00:00:00 2001 From: Nigel Ihza Firdausy <106657905+Ni-zav@users.noreply.github.com> Date: Mon, 12 Oct 2026 15:10:55 +0700 Subject: [PATCH] fix(transform): keep nearest-neighbor previews on original texels (#3688) --- crates/ui-egui/src/transform_tex.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/crates/ui-egui/src/transform_tex.rs b/crates/ui-egui/src/transform_tex.rs index 2811a6b586..e1ddb504bf 100644 --- a/crates/ui-egui/src/transform_tex.rs +++ b/crates/ui-egui/src/transform_tex.rs @@ -58,11 +58,16 @@ impl PreviewTextures { if !s.is_finite() || s <= 0.0 { return (0, false); } + // Nearest Neighbor is point sampling: downsampled mip levels have already averaged + // neighbouring texels, so using one would blur a pixel-art transform preview. + if nearest_interpolation { + return (0, true); + } if s < 0.5 { // log2(1/s) levels down, at most 12 (4096× smaller). - return ((1.0 / s).log2().floor().clamp(0.0, 12.0) as u32, nearest_interpolation); + return ((1.0 / s).log2().floor().clamp(0.0, 12.0) as u32, false); } - let crisp = nearest_interpolation || (zoom >= CRISP_ZOOM && scale <= 1.05); + let crisp = zoom >= CRISP_ZOOM && scale <= 1.05; (0, crisp) } @@ -203,6 +208,10 @@ mod tests { assert_eq!(PreviewTextures::choose(1.0, 1.0, true), (0, true)); assert_eq!(PreviewTextures::choose(0.25, 1.0, false), (2, false)); assert_eq!(PreviewTextures::choose(0.3, 1.0, false), (1, false)); + // Nearest Neighbor must use the full-resolution texels, even when zoomed far out. + // A mipmap would average adjacent opaque/transparent pixels before sampling. + assert_eq!(PreviewTextures::choose(0.25, 1.0, true), (0, true)); + assert_eq!(PreviewTextures::choose(1.0 / 4096.0, 1.0, true), (0, true)); assert_eq!(PreviewTextures::choose(f32::NAN, 1.0, false), (0, false)); assert_eq!(PreviewTextures::choose(1e-9, 1.0, false).0, 12); }