pub struct TextureCache {
pub textures: Vec<wgpu::Texture>,
pub views: Vec<wgpu::TextureView>,
pub default_white_view: wgpu::TextureView,
pub default_normal_view: wgpu::TextureView,
pub sampler: wgpu::Sampler,
_default_white: wgpu::Texture,
_default_normal: wgpu::Texture,
}
impl TextureCache {
pub fn new(device: &wgpu::Device, queue: &wgpu::Queue) -> Self {
let default_white = device.create_texture(&wgpu::TextureDescriptor {
label: Some("Default White Texture"),
size: wgpu::Extent3d {
width: 1,
height: 1,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8UnormSrgb,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
view_formats: &[],
});
queue.write_texture(
wgpu::TexelCopyTextureInfo {
texture: &default_white,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
aspect: wgpu::TextureAspect::All,
},
&[255, 255, 255, 255],
wgpu::TexelCopyBufferLayout {
offset: 0,
bytes_per_row: Some(4),
rows_per_image: Some(1),
},
wgpu::Extent3d {
width: 1,
height: 1,
depth_or_array_layers: 1,
},
);
let default_white_view = default_white.create_view(&wgpu::TextureViewDescriptor::default());
let default_normal = device.create_texture(&wgpu::TextureDescriptor {
label: Some("Default Normal Texture"),
size: wgpu::Extent3d {
width: 1,
height: 1,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8Unorm,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
view_formats: &[],
});
queue.write_texture(
wgpu::TexelCopyTextureInfo {
texture: &default_normal,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
aspect: wgpu::TextureAspect::All,
},
&[128, 128, 255, 255],
wgpu::TexelCopyBufferLayout {
offset: 0,
bytes_per_row: Some(4),
rows_per_image: Some(1),
},
wgpu::Extent3d {
width: 1,
height: 1,
depth_or_array_layers: 1,
},
);
let default_normal_view =
default_normal.create_view(&wgpu::TextureViewDescriptor::default());
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
label: Some("Material Sampler"),
address_mode_u: wgpu::AddressMode::Repeat,
address_mode_v: wgpu::AddressMode::Repeat,
address_mode_w: wgpu::AddressMode::Repeat,
mag_filter: wgpu::FilterMode::Linear,
min_filter: wgpu::FilterMode::Linear,
mipmap_filter: wgpu::FilterMode::Linear,
lod_min_clamp: 0.0,
lod_max_clamp: 100.0,
compare: None,
anisotropy_clamp: 16,
border_color: None,
});
Self {
textures: Vec::new(),
views: Vec::new(),
default_white_view,
default_normal_view,
sampler,
_default_white: default_white,
_default_normal: default_normal,
}
}
pub fn upload_image(
&mut self,
device: &wgpu::Device,
queue: &wgpu::Queue,
image: &image::RgbaImage,
label: &str,
srgb: bool,
) -> usize {
let (width, height) = image.dimensions();
let format = if srgb {
wgpu::TextureFormat::Rgba8UnormSrgb
} else {
wgpu::TextureFormat::Rgba8Unorm
};
let texture = device.create_texture(&wgpu::TextureDescriptor {
label: Some(label),
size: wgpu::Extent3d {
width,
height,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
view_formats: &[],
});
queue.write_texture(
wgpu::TexelCopyTextureInfo {
texture: &texture,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
aspect: wgpu::TextureAspect::All,
},
image.as_raw(),
wgpu::TexelCopyBufferLayout {
offset: 0,
bytes_per_row: Some(width * 4),
rows_per_image: Some(height),
},
wgpu::Extent3d {
width,
height,
depth_or_array_layers: 1,
},
);
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
let index = self.textures.len();
self.textures.push(texture);
self.views.push(view);
index
}
pub fn get_view(&self, index: Option<usize>) -> &wgpu::TextureView {
match index {
Some(i) if i < self.views.len() => &self.views[i],
_ => &self.default_white_view,
}
}
pub fn get_normal_view(&self, index: Option<usize>) -> &wgpu::TextureView {
match index {
Some(i) if i < self.views.len() => &self.views[i],
_ => &self.default_normal_view,
}
}
}