use image::GenericImageView; use wgpu::util::DeviceExt; pub struct Texture { pub texture: wgpu::Texture, pub view: wgpu::TextureView, pub sampler: wgpu::Sampler, } impl Texture { pub fn from_bytes( device: &wgpu::Device, bytes: &[u8], label: &str, ) -> Result<(Self, wgpu::CommandBuffer), failure::Error> { let img = image::load_from_memory(bytes)?; Self::from_image(device, &img, Some(label)) } pub fn from_image( device: &wgpu::Device, img: &image::DynamicImage, label: Option<&str>, ) -> Result<(Self, wgpu::CommandBuffer), failure::Error> { let rgba = img.as_rgba8().unwrap(); let (width, height) = img.dimensions(); let size = wgpu::Extent3d { width, height, depth: 1, }; let texture = device.create_texture(&wgpu::TextureDescriptor { label, size, mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D2, format: wgpu::TextureFormat::Rgba8UnormSrgb, usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::COPY_DST, }); let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("texture_buffer"), contents: &rgba, usage: wgpu::BufferUsage::COPY_SRC, }); let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("texture_buffer_copy_encoder"), }); encoder.copy_buffer_to_texture( wgpu::BufferCopyView { buffer: &buffer, layout: wgpu::TextureDataLayout { offset: 0, bytes_per_row: 4 * width, rows_per_image: height, }, }, wgpu::TextureCopyView { texture: &texture, mip_level: 0, origin: wgpu::Origin3d::ZERO, }, size, ); let command = encoder.finish(); let view = texture.create_view(&Default::default()); let sampler = device.create_sampler(&wgpu::SamplerDescriptor { label: Some("texture_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::Nearest, mipmap_filter: wgpu::FilterMode::Nearest, lod_min_clamp: -100.0, lod_max_clamp: 100.0, compare: None, anisotropy_clamp: None, }); Ok(( Texture { texture, view, sampler, }, command, )) } pub const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; pub fn create_depth_texture( device: &wgpu::Device, sc_desc: &wgpu::SwapChainDescriptor, label: &str, ) -> Self { let size = wgpu::Extent3d { width: sc_desc.width, height: sc_desc.height, depth: 1, }; let desc = wgpu::TextureDescriptor { label: Some(label), size, mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D2, format: Self::DEPTH_FORMAT, usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT | wgpu::TextureUsage::SAMPLED, }; let texture = device.create_texture(&desc); let view = texture.create_view(&wgpu::TextureViewDescriptor::default()); 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::Nearest, lod_min_clamp: -100.0, lod_max_clamp: 100.0, compare: Some(wgpu::CompareFunction::LessEqual), ..Default::default() }); Self { texture, view, sampler, } } }