fj_viewer/graphics/
texture.rs1use image::{GenericImageView, ImageError};
2
3#[derive(Debug)]
4pub struct Texture {
5 pub texture: wgpu::Texture,
6 pub view: wgpu::TextureView,
7 pub sampler: wgpu::Sampler,
8}
9
10#[derive(Debug, thiserror::Error)]
11pub enum LoadTextureError {
12 #[error("Image processing error")]
13 ImageError(#[from] ImageError),
14}
15
16impl Texture {
17 pub fn from_bytes(
18 device: &wgpu::Device,
19 queue: &wgpu::Queue,
20 bytes: &[u8],
21 label: &str,
22 ) -> Result<Self, LoadTextureError> {
23 let img = image::load_from_memory(bytes)?;
24 Ok(Self::from_image(device, queue, &img, Some(label)))
25 }
26
27 pub fn from_image(
28 device: &wgpu::Device,
29 queue: &wgpu::Queue,
30 img: &image::DynamicImage,
31 label: Option<&str>,
32 ) -> Self {
33 let dimensions = img.dimensions();
34 let rgba = img.to_rgba8();
35
36 let size = wgpu::Extent3d {
37 width: dimensions.0,
38 height: dimensions.1,
39 depth_or_array_layers: 1,
40 };
41 let texture = device.create_texture(&wgpu::TextureDescriptor {
42 label,
43 size,
44 mip_level_count: 1,
45 sample_count: 1,
46 dimension: wgpu::TextureDimension::D2,
47 format: wgpu::TextureFormat::Rgba8UnormSrgb,
48 usage: wgpu::TextureUsages::TEXTURE_BINDING
49 | wgpu::TextureUsages::COPY_DST,
50 view_formats: &[],
51 });
52
53 queue.write_texture(
54 wgpu::ImageCopyTexture {
55 aspect: wgpu::TextureAspect::All,
56 texture: &texture,
57 mip_level: 0,
58 origin: wgpu::Origin3d::ZERO,
59 },
60 &rgba,
61 wgpu::ImageDataLayout {
62 offset: 0,
63 bytes_per_row: Some(4 * dimensions.0),
64 rows_per_image: Some(dimensions.1),
65 },
66 size,
67 );
68
69 let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
70 let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
71 address_mode_u: wgpu::AddressMode::ClampToEdge,
72 address_mode_v: wgpu::AddressMode::ClampToEdge,
73 address_mode_w: wgpu::AddressMode::ClampToEdge,
74 mag_filter: wgpu::FilterMode::Linear,
75 min_filter: wgpu::FilterMode::Nearest,
76 mipmap_filter: wgpu::FilterMode::Nearest,
77 ..Default::default()
78 });
79
80 Self {
81 texture,
82 view,
83 sampler,
84 }
85 }
86}