1use super::RenderError;
2use image::DynamicImage;
3use wgpu::Extent3d;
4
5pub struct Texture {
7 pub tex: wgpu::Texture,
8 pub view: wgpu::TextureView,
9 pub sampler: wgpu::Sampler,
10 size: Extent3d,
11 format: wgpu::TextureFormat,
13}
14
15impl Texture {
16 pub fn new(
17 device: &wgpu::Device,
18 queue: &wgpu::Queue,
19 image: &DynamicImage,
20 filter_method: Option<wgpu::FilterMode>,
21 address_mode: Option<wgpu::AddressMode>,
22 ) -> Result<Self, RenderError> {
23 let format = match image {
24 DynamicImage::ImageLuma8(_) => wgpu::TextureFormat::R8Unorm,
25 DynamicImage::ImageLumaA8(_) => panic!("ImageLuma8 unsupported"),
26 DynamicImage::ImageRgb8(_) => panic!("ImageRgb8 unsupported"),
27 DynamicImage::ImageRgba8(_) => wgpu::TextureFormat::Rgba8UnormSrgb,
28 DynamicImage::ImageLuma16(_) => panic!("ImageLuma16 unsupported"),
29 DynamicImage::ImageLumaA16(_) => panic!("ImageLumaA16 unsupported"),
30 DynamicImage::ImageRgb16(_) => panic!("ImageRgb16 unsupported"),
31 DynamicImage::ImageRgba16(_) => panic!("ImageRgba16 unsupported"),
32 _ => panic!("unsupported format"),
33 };
34
35 let buffer = image.as_flat_samples_u8().ok_or_else(|| {
37 RenderError::CustomError(
38 "We currently do not support color formats using more than 4 bytes / pixel.".into(),
39 )
40 })?;
41
42 let bytes_per_pixel = u32::from(buffer.layout.channels);
43
44 let size = Extent3d {
45 width: image.width(),
46 height: image.height(),
47 depth_or_array_layers: 1,
48 };
49
50 let tex = device.create_texture(&wgpu::TextureDescriptor {
51 label: None,
52 size,
53 mip_level_count: 1,
54 sample_count: 1,
55 dimension: wgpu::TextureDimension::D2,
56 format,
57 usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
58 view_formats: &[],
59 });
60
61 queue.write_texture(
62 wgpu::ImageCopyTexture {
63 texture: &tex,
64 mip_level: 0,
65 origin: wgpu::Origin3d::ZERO,
66 aspect: wgpu::TextureAspect::All,
67 },
68 buffer.as_slice(),
69 wgpu::ImageDataLayout {
70 offset: 0,
71 bytes_per_row: Some(image.width() * bytes_per_pixel),
72 rows_per_image: Some(image.height()),
73 },
74 Extent3d {
75 width: image.width(),
76 height: image.height(),
77 depth_or_array_layers: 1,
78 },
79 );
80
81 let sampler_info = wgpu::SamplerDescriptor {
82 label: None,
83 address_mode_u: address_mode.unwrap_or(wgpu::AddressMode::ClampToEdge),
84 address_mode_v: address_mode.unwrap_or(wgpu::AddressMode::ClampToEdge),
85 address_mode_w: address_mode.unwrap_or(wgpu::AddressMode::ClampToEdge),
86 mag_filter: filter_method.unwrap_or(wgpu::FilterMode::Nearest),
87 min_filter: filter_method.unwrap_or(wgpu::FilterMode::Nearest),
88 mipmap_filter: wgpu::FilterMode::Nearest,
89 ..Default::default()
90 };
91
92 let view = tex.create_view(&wgpu::TextureViewDescriptor {
93 label: None,
94 format: Some(format),
95 dimension: Some(wgpu::TextureViewDimension::D2),
96 aspect: wgpu::TextureAspect::All,
97 base_mip_level: 0,
98 mip_level_count: None,
99 base_array_layer: 0,
100 array_layer_count: None,
101 });
102
103 Ok(Self {
104 tex,
105 view,
106 sampler: device.create_sampler(&sampler_info),
107 size,
108 format,
109 })
110 }
111
112 pub fn new_dynamic(
113 device: &wgpu::Device,
114 queue: &wgpu::Queue,
115 width: u32,
116 height: u32,
117 ) -> Self {
118 let size = Extent3d {
119 width,
120 height,
121 depth_or_array_layers: 1,
122 };
123
124 let tex_info = wgpu::TextureDescriptor {
125 label: None,
126 size,
127 mip_level_count: 1,
128 sample_count: 1,
129 dimension: wgpu::TextureDimension::D2,
130 format: wgpu::TextureFormat::Rgba8UnormSrgb,
131 usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
133 view_formats: &[],
134 };
135
136 let sampler_info = wgpu::SamplerDescriptor {
137 label: None,
138 address_mode_u: wgpu::AddressMode::ClampToEdge,
139 address_mode_v: wgpu::AddressMode::ClampToEdge,
140 address_mode_w: wgpu::AddressMode::ClampToEdge,
141 mag_filter: wgpu::FilterMode::Linear,
142 min_filter: wgpu::FilterMode::Linear,
143 mipmap_filter: wgpu::FilterMode::Nearest,
144 ..Default::default()
145 };
146
147 let view_info = wgpu::TextureViewDescriptor {
148 label: None,
149 format: Some(wgpu::TextureFormat::Rgba8UnormSrgb),
150 dimension: Some(wgpu::TextureViewDimension::D2),
151 aspect: wgpu::TextureAspect::All,
152 base_mip_level: 0,
153 mip_level_count: None,
154 base_array_layer: 0,
155 array_layer_count: None,
156 };
157
158 let texture = Self::new_raw(device, &tex_info, &view_info, &sampler_info);
159 texture.clear(queue); texture
161 }
162
163 pub fn new_raw(
166 device: &wgpu::Device,
167 texture_info: &wgpu::TextureDescriptor,
168 view_info: &wgpu::TextureViewDescriptor,
169 sampler_info: &wgpu::SamplerDescriptor,
170 ) -> Self {
171 let tex = device.create_texture(texture_info);
172 let view = tex.create_view(view_info);
173
174 Self {
175 tex,
176 view,
177 sampler: device.create_sampler(sampler_info),
178 size: texture_info.size,
179 format: texture_info.format,
180 }
181 }
182
183 pub fn clear(&self, queue: &wgpu::Queue) {
185 let size = self.size;
186 let byte_len = size.width as usize
187 * size.height as usize
188 * size.depth_or_array_layers as usize
189 * self.format.block_size(None).unwrap() as usize;
190 let zeros = vec![0; byte_len];
191
192 self.update(queue, [0, 0], [size.width, size.height], &zeros);
193 }
194
195 pub fn update(&self, queue: &wgpu::Queue, offset: [u32; 2], size: [u32; 2], data: &[u8]) {
198 let bytes_per_pixel = self.format.block_size(None).unwrap();
199
200 debug_assert_eq!(
201 data.len(),
202 size[0] as usize * size[1] as usize * bytes_per_pixel as usize
203 );
204 queue.write_texture(
206 wgpu::ImageCopyTexture {
207 texture: &self.tex,
208 mip_level: 0,
209 origin: wgpu::Origin3d {
210 x: offset[0],
211 y: offset[1],
212 z: 0,
213 },
214 aspect: wgpu::TextureAspect::All,
215 },
216 data,
217 wgpu::ImageDataLayout {
218 offset: 0,
219 bytes_per_row: Some(size[0] * bytes_per_pixel),
220 rows_per_image: Some(size[1]),
221 },
222 Extent3d {
223 width: size[0],
224 height: size[1],
225 depth_or_array_layers: 1,
226 },
227 );
228 }
229
230 pub fn get_dimensions(&self) -> vek::Vec3<u32> {
233 vek::Vec3::new(
234 self.size.width,
235 self.size.height,
236 self.size.depth_or_array_layers,
237 )
238 }
239}