witchcraft_renderer/types/
texture.rs

1use image::GenericImageView;
2
3/// An abstraction for a texture.
4pub struct Texture {
5    pub texture: wgpu::Texture,
6    pub view: wgpu::TextureView,
7    pub sampler: wgpu::Sampler,
8}
9impl Texture {
10    pub fn from_bytes(
11        label: &str,
12        device: &wgpu::Device,
13        queue: &wgpu::Queue,
14        bytes: &[u8],
15    ) -> anyhow::Result<Self> {
16        let img = image::load_from_memory(bytes)?;
17        Self::from_image(label, device, queue, &img)
18    }
19
20    pub fn from_image(
21        label: &str,
22        device: &wgpu::Device,
23        queue: &wgpu::Queue,
24        img: &image::DynamicImage,
25    ) -> anyhow::Result<Self> {
26        let rgba = img.to_rgba8();
27        let dimensions = img.dimensions();
28
29        let size = wgpu::Extent3d {
30            width: dimensions.0,
31            height: dimensions.1,
32            depth_or_array_layers: 1,
33        };
34
35        let texture = device.create_texture(&wgpu::TextureDescriptor {
36            label: Some(label),
37            size,
38            mip_level_count: 1,
39            sample_count: 1,
40            dimension: wgpu::TextureDimension::D2,
41            format: wgpu::TextureFormat::Rgba8UnormSrgb,
42            usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
43        });
44
45        queue.write_texture(
46            wgpu::ImageCopyTexture {
47                aspect: wgpu::TextureAspect::All,
48                texture: &texture,
49                mip_level: 0,
50                origin: wgpu::Origin3d::ZERO,
51            },
52            &rgba,
53            wgpu::ImageDataLayout {
54                offset: 0,
55                bytes_per_row: std::num::NonZeroU32::new(4 * dimensions.0),
56                rows_per_image: std::num::NonZeroU32::new(dimensions.1),
57            },
58            size,
59        );
60
61        let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
62        let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
63            address_mode_u: wgpu::AddressMode::ClampToEdge,
64            address_mode_v: wgpu::AddressMode::ClampToEdge,
65            address_mode_w: wgpu::AddressMode::ClampToEdge,
66            mag_filter: wgpu::FilterMode::Linear,
67            min_filter: wgpu::FilterMode::Nearest,
68            mipmap_filter: wgpu::FilterMode::Nearest,
69            ..Default::default()
70        });
71
72        Ok(Self {
73            texture,
74            view,
75            sampler,
76        })
77    }
78
79    pub const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float;
80
81    pub fn create_depth_texture(
82        label: &str,
83        device: &wgpu::Device,
84        config: &wgpu::SurfaceConfiguration,
85    ) -> Self {
86        let size = wgpu::Extent3d {
87            width: config.width,
88            height: config.height,
89            depth_or_array_layers: 1,
90        };
91
92        let desc = wgpu::TextureDescriptor {
93            label: Some(label),
94            size,
95            mip_level_count: 1,
96            sample_count: 1,
97            dimension: wgpu::TextureDimension::D2,
98            format: Self::DEPTH_FORMAT,
99            usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING,
100        };
101
102        let texture = device.create_texture(&desc);
103        let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
104        let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
105            address_mode_u: wgpu::AddressMode::ClampToEdge,
106            address_mode_v: wgpu::AddressMode::ClampToEdge,
107            address_mode_w: wgpu::AddressMode::ClampToEdge,
108            mag_filter: wgpu::FilterMode::Linear,
109            min_filter: wgpu::FilterMode::Linear,
110            mipmap_filter: wgpu::FilterMode::Nearest,
111            compare: Some(wgpu::CompareFunction::LessEqual),
112            lod_min_clamp: -100.0,
113            lod_max_clamp: 100.0,
114            ..Default::default()
115        });
116
117        Self {
118            texture,
119            view,
120            sampler,
121        }
122    }
123}