Implement texture filtering options
This commit is contained in:
parent
ef015a5e72
commit
5759096a4c
4 changed files with 84 additions and 26 deletions
|
|
@ -5,11 +5,31 @@ use std::hash::{Hash, Hasher as _};
|
|||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Image filter method
|
||||
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum FilterMethod {
|
||||
/// Bilinear interpolation
|
||||
#[default]
|
||||
Linear,
|
||||
/// Nearest Neighbor
|
||||
Nearest,
|
||||
}
|
||||
|
||||
/// Texture filter settings
|
||||
#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct TextureFilter {
|
||||
/// Filter for scaling the image down.
|
||||
pub min: FilterMethod,
|
||||
/// Filter for scaling the image up.
|
||||
pub mag: FilterMethod,
|
||||
}
|
||||
|
||||
/// A handle of some image data.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Handle {
|
||||
id: u64,
|
||||
data: Data,
|
||||
filter: TextureFilter,
|
||||
}
|
||||
|
||||
impl Handle {
|
||||
|
|
@ -56,6 +76,7 @@ impl Handle {
|
|||
Handle {
|
||||
id: hasher.finish(),
|
||||
data,
|
||||
filter: TextureFilter::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -68,6 +89,17 @@ impl Handle {
|
|||
pub fn data(&self) -> &Data {
|
||||
&self.data
|
||||
}
|
||||
|
||||
/// Returns a reference to the [`TextureFilter`].
|
||||
pub fn filter(&self) -> &TextureFilter {
|
||||
&self.filter
|
||||
}
|
||||
|
||||
/// Sets the texture filtering methods.
|
||||
pub fn set_filter(mut self, filter: TextureFilter) -> Self {
|
||||
self.filter = filter;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for Handle
|
||||
|
|
|
|||
|
|
@ -39,12 +39,17 @@ impl Pipeline {
|
|||
|
||||
let transform = transform.pre_scale(width_scale, height_scale);
|
||||
|
||||
let quality = match handle.filter().mag {
|
||||
raster::FilterMethod::Linear => tiny_skia::FilterQuality::Bilinear,
|
||||
raster::FilterMethod::Nearest => tiny_skia::FilterQuality::Nearest,
|
||||
};
|
||||
|
||||
pixels.draw_pixmap(
|
||||
(bounds.x / width_scale) as i32,
|
||||
(bounds.y / height_scale) as i32,
|
||||
image,
|
||||
&tiny_skia::PixmapPaint {
|
||||
quality: tiny_skia::FilterQuality::Bilinear,
|
||||
quality: quality,
|
||||
..Default::default()
|
||||
},
|
||||
transform,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ mod raster;
|
|||
mod vector;
|
||||
|
||||
use atlas::Atlas;
|
||||
use iced_graphics::core::image::{TextureFilter, FilterMethod};
|
||||
|
||||
use crate::core::{Rectangle, Size};
|
||||
use crate::graphics::Transformation;
|
||||
|
|
@ -14,6 +15,7 @@ use crate::layer;
|
|||
use crate::Buffer;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::mem;
|
||||
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
|
|
@ -37,7 +39,7 @@ pub struct Pipeline {
|
|||
pipeline: wgpu::RenderPipeline,
|
||||
vertices: wgpu::Buffer,
|
||||
indices: wgpu::Buffer,
|
||||
sampler: wgpu::Sampler,
|
||||
sampler: HashMap<TextureFilter,wgpu::Sampler>,
|
||||
texture: wgpu::BindGroup,
|
||||
texture_version: usize,
|
||||
texture_atlas: Atlas,
|
||||
|
|
@ -142,15 +144,32 @@ impl Pipeline {
|
|||
pub fn new(device: &wgpu::Device, format: wgpu::TextureFormat) -> Self {
|
||||
use wgpu::util::DeviceExt;
|
||||
|
||||
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
|
||||
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::FilterMode::Linear,
|
||||
..Default::default()
|
||||
});
|
||||
let to_wgpu = |method: FilterMethod| {
|
||||
match method {
|
||||
FilterMethod::Linear => wgpu::FilterMode::Linear,
|
||||
FilterMethod::Nearest => wgpu::FilterMode::Nearest,
|
||||
}
|
||||
};
|
||||
|
||||
let mut sampler = HashMap::new();
|
||||
|
||||
let filter = [FilterMethod::Linear, FilterMethod::Nearest];
|
||||
for min in 0..filter.len() {
|
||||
for mag in 0..filter.len() {
|
||||
let _ = sampler.insert(TextureFilter {min: filter[min], mag: filter[mag]},
|
||||
device.create_sampler(&wgpu::SamplerDescriptor {
|
||||
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
||||
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
||||
address_mode_w: wgpu::AddressMode::ClampToEdge,
|
||||
mag_filter: to_wgpu(filter[mag]),
|
||||
min_filter: to_wgpu(filter[min]),
|
||||
mipmap_filter: wgpu::FilterMode::Linear,
|
||||
..Default::default()
|
||||
}
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let constant_layout =
|
||||
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
|
|
@ -355,7 +374,7 @@ impl Pipeline {
|
|||
#[cfg(feature = "tracing")]
|
||||
let _ = info_span!("Wgpu::Image", "DRAW").entered();
|
||||
|
||||
let instances: &mut Vec<Instance> = &mut Vec::new();
|
||||
let instances: &mut HashMap<TextureFilter,Vec<Instance>> = &mut HashMap::new();
|
||||
|
||||
#[cfg(feature = "image")]
|
||||
let mut raster_cache = self.raster_cache.borrow_mut();
|
||||
|
|
@ -377,7 +396,7 @@ impl Pipeline {
|
|||
[bounds.x, bounds.y],
|
||||
[bounds.width, bounds.height],
|
||||
atlas_entry,
|
||||
instances,
|
||||
instances.entry(handle.filter().clone()).or_insert(Vec::new()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -405,7 +424,7 @@ impl Pipeline {
|
|||
[bounds.x, bounds.y],
|
||||
size,
|
||||
atlas_entry,
|
||||
instances,
|
||||
instances.entry(TextureFilter::default()).or_insert(Vec::new()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -438,18 +457,20 @@ impl Pipeline {
|
|||
self.texture_version = texture_version;
|
||||
}
|
||||
|
||||
if self.layers.len() <= self.prepare_layer {
|
||||
self.layers.push(Layer::new(
|
||||
device,
|
||||
&self.constant_layout,
|
||||
&self.sampler,
|
||||
));
|
||||
for (filter, instances) in instances.iter_mut() {
|
||||
if self.layers.len() <= self.prepare_layer {
|
||||
self.layers.push(Layer::new(
|
||||
device,
|
||||
&self.constant_layout,
|
||||
&self.sampler.get(filter).expect("Sampler is registered"),
|
||||
));
|
||||
}
|
||||
|
||||
let layer = &mut self.layers[self.prepare_layer];
|
||||
layer.prepare(device, queue, &instances, transformation);
|
||||
|
||||
self.prepare_layer += 1;
|
||||
}
|
||||
|
||||
let layer = &mut self.layers[self.prepare_layer];
|
||||
layer.prepare(device, queue, instances, transformation);
|
||||
|
||||
self.prepare_layer += 1;
|
||||
}
|
||||
|
||||
pub fn render<'a>(
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use crate::core::{
|
|||
|
||||
use std::hash::Hash;
|
||||
|
||||
pub use image::Handle;
|
||||
pub use image::{Handle, TextureFilter, FilterMethod};
|
||||
|
||||
/// Creates a new [`Viewer`] with the given image `Handle`.
|
||||
pub fn viewer<Handle>(handle: Handle) -> Viewer<Handle> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue