1pub struct TextureSpec {
2 pub width: u32,
3 pub height: u32,
4 pub format: wgpu::TextureFormat,
5 pub data: Vec<u8>,
9 pub generate_mips: bool,
10}
11
12impl TextureSpec {
13 pub fn mip_level_count(&self) -> u32 {
16 if self.generate_mips {
17 32 - self.width.max(self.height).max(1).leading_zeros()
18 } else {
19 1
20 }
21 }
22
23 pub fn wgpu_descriptor(&self) -> wgpu::TextureDescriptor<'static> {
27 wgpu::TextureDescriptor {
28 label: None,
29 size: wgpu::Extent3d {
30 width: self.width,
31 height: self.height,
32 depth_or_array_layers: 1,
33 },
34 mip_level_count: self.mip_level_count(),
35 sample_count: 1,
36 dimension: wgpu::TextureDimension::D2,
37 format: self.format,
38 usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
39 view_formats: &[],
40 }
41 }
42
43 pub fn downsample(data: &[u8], width: u32, height: u32) -> (Vec<u8>, u32, u32) {
49 let next_width = (width / 2).max(1);
50 let next_height = (height / 2).max(1);
51 let mut out = vec![0u8; (next_width * next_height * 4) as usize];
52
53 for y in 0..next_height {
54 for x in 0..next_width {
55 let x0 = (x * 2).min(width - 1);
56 let x1 = (x * 2 + 1).min(width - 1);
57 let y0 = (y * 2).min(height - 1);
58 let y1 = (y * 2 + 1).min(height - 1);
59
60 for c in 0..4 {
61 let sample = |sx: u32, sy: u32| -> u32 {
62 data[((sy * width + sx) * 4 + c) as usize] as u32
63 };
64 let avg = (sample(x0, y0) + sample(x1, y0) + sample(x0, y1) + sample(x1, y1))
65 / 4;
66 out[((y * next_width + x) * 4 + c) as usize] = avg as u8;
67 }
68 }
69 }
70
71 (out, next_width, next_height)
72 }
73}
74
75impl TextureSpec {
76 pub fn new(width: u32, height: u32, data: Vec<u8>, generate_mips: bool) -> Self {
77 Self {
78 width,
79 height,
80 format: wgpu::TextureFormat::Rgba8Unorm,
81 data,
82 generate_mips,
83 }
84 }
85
86 pub fn with_format(mut self, format: wgpu::TextureFormat) -> Self {
87 self.format = format;
88 self
89 }
90}