From 46fa08a0417fe099daf099a6e38ca97c2df6a66a Mon Sep 17 00:00:00 2001 From: ramox81 <184937705+ramox81@users.noreply.github.com> Date: Fri, 25 Sep 2026 12:22:45 +0300 Subject: [PATCH] Raster images show square pixels when magnified Raster image textures use nearest magnification; PDF pages and OLE pictures keep bilinear filtering. Co-Authored-By: Claude Opus 5.5 --- src/scene/model/image_model.rs | 6 ++++++ src/scene/pipeline/image_gpu.rs | 32 ++++++++++++++++++++------------ 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/scene/model/image_model.rs b/src/scene/model/image_model.rs index e99743fd4..4b23828c4 100644 --- a/src/scene/model/image_model.rs +++ b/src/scene/model/image_model.rs @@ -109,6 +109,9 @@ pub struct ImageModel { /// (when the entity carries a clip boundary) the triangulated clip polygon /// — so the raster is drawn only inside its clip boundary. pub verts: Vec, + /// Magnified pixels stay square (raster images); otherwise they blend + /// (PDF pages, OLE pictures). + pub pixelated: bool, } impl ImageModel { @@ -179,6 +182,7 @@ impl ImageModel { corners_low, draw_depth: 0.0, verts, + pixelated: true, }) } } @@ -283,6 +287,7 @@ impl ImageModel { corners_low, draw_depth: 0.0, verts, + pixelated: false, }) } } @@ -363,6 +368,7 @@ impl ImageModel { corners_low, draw_depth: 0.0, verts, + pixelated: false, }) } } diff --git a/src/scene/pipeline/image_gpu.rs b/src/scene/pipeline/image_gpu.rs index 284a207f1..196c3f830 100644 --- a/src/scene/pipeline/image_gpu.rs +++ b/src/scene/pipeline/image_gpu.rs @@ -2,7 +2,7 @@ // // Group 1 bindings per image: // binding 0 — texture_2d (RGBA image texture) -// binding 1 — sampler (bilinear filtering) +// binding 1 — sampler (bilinear; nearest magnification for raster images) // binding 2 — ImageParams (opacity uniform, 16 bytes) use crate::scene::model::image_model::ImageModel; @@ -118,19 +118,27 @@ impl ImageGpu { }); groups[slot].push(model); } - let sampler = Arc::new(device.create_sampler(&wgpu::SamplerDescriptor { - label: Some("image.sampler"), - address_mode_u: wgpu::AddressMode::ClampToEdge, - address_mode_v: wgpu::AddressMode::ClampToEdge, - address_mode_w: wgpu::AddressMode::ClampToEdge, - mag_filter: wgpu::FilterMode::Linear, - min_filter: wgpu::FilterMode::Linear, - mipmap_filter: wgpu::MipmapFilterMode::Nearest, - ..Default::default() - })); + let sampler = |mag_filter| { + Arc::new(device.create_sampler(&wgpu::SamplerDescriptor { + label: Some("image.sampler"), + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + mag_filter, + min_filter: wgpu::FilterMode::Linear, + mipmap_filter: wgpu::MipmapFilterMode::Nearest, + ..Default::default() + })) + }; + // Raster images show square pixels when magnified. + let smooth = sampler(wgpu::FilterMode::Linear); + let pixelated = sampler(wgpu::FilterMode::Nearest); groups .into_iter() - .flat_map(|group| Self::new(device, queue, &group, bgl1, &sampler)) + .flat_map(|group| { + let sampler = if group.first().is_some_and(|m| m.pixelated) { &pixelated } else { &smooth }; + Self::new(device, queue, &group, bgl1, sampler) + }) .collect() }