1use banished_formats::texture::decode_rgba;
4use banished_formats::types::ImageBuffer;
5
6pub fn upload_rgba(
8 device: &wgpu::Device,
9 queue: &wgpu::Queue,
10 label: &str,
11 width: u32,
12 height: u32,
13 mips: &[Vec<u8>],
14) -> wgpu::TextureView {
15 upload_rgba_as(
16 device,
17 queue,
18 label,
19 width,
20 height,
21 mips,
22 wgpu::TextureFormat::Rgba8UnormSrgb,
23 )
24}
25
26pub fn upload_rgba_as(
28 device: &wgpu::Device,
29 queue: &wgpu::Queue,
30 label: &str,
31 width: u32,
32 height: u32,
33 mips: &[Vec<u8>],
34 format: wgpu::TextureFormat,
35) -> wgpu::TextureView {
36 let texture = device.create_texture(&wgpu::TextureDescriptor {
37 label: Some(label),
38 size: wgpu::Extent3d {
39 width,
40 height,
41 depth_or_array_layers: 1,
42 },
43 mip_level_count: mips.len() as u32,
44 sample_count: 1,
45 dimension: wgpu::TextureDimension::D2,
46 format,
47 usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
48 view_formats: &[],
49 });
50 for (level, data) in mips.iter().enumerate() {
51 let (w, h) = ((width >> level).max(1), (height >> level).max(1));
52 queue.write_texture(
53 wgpu::TexelCopyTextureInfo {
54 texture: &texture,
55 mip_level: level as u32,
56 origin: wgpu::Origin3d::ZERO,
57 aspect: wgpu::TextureAspect::All,
58 },
59 data,
60 wgpu::TexelCopyBufferLayout {
61 offset: 0,
62 bytes_per_row: Some(w * 4),
63 rows_per_image: Some(h),
64 },
65 wgpu::Extent3d {
66 width: w,
67 height: h,
68 depth_or_array_layers: 1,
69 },
70 );
71 }
72 texture.create_view(&Default::default())
73}
74
75pub fn upload_image(
77 device: &wgpu::Device,
78 queue: &wgpu::Queue,
79 label: &str,
80 img: &ImageBuffer,
81) -> Option<wgpu::TextureView> {
82 let mips: Option<Vec<Vec<u8>>> = img.levels[..img.mip_count()]
83 .iter()
84 .enumerate()
85 .map(|(i, level)| decode_rgba(img.format, img.width >> i, img.height >> i, level))
86 .collect();
87 let mips = mips?;
88 if mips.is_empty() {
89 return None;
90 }
91 Some(upload_rgba(
92 device, queue, label, img.width, img.height, &mips,
93 ))
94}
95
96pub fn decode_levels(img: &ImageBuffer) -> Option<Vec<Vec<u8>>> {
98 let mips = img.mip_count().max(1);
99 let mut out = Vec::with_capacity(img.faces() * mips);
100 for face in 0..img.faces() {
101 for mip in 0..mips {
102 let level = img.levels.get(face * mips + mip)?;
103 let (w, h) = ((img.width >> mip).max(1), (img.height >> mip).max(1));
104 out.push(decode_rgba(img.format, w, h, level)?);
105 }
106 }
107 Some(out)
108}
109
110pub fn upload_image_linear(
112 device: &wgpu::Device,
113 queue: &wgpu::Queue,
114 label: &str,
115 img: &ImageBuffer,
116) -> Option<wgpu::TextureView> {
117 let levels = decode_levels(img)?;
118 Some(upload_rgba_as(
119 device,
120 queue,
121 label,
122 img.width,
123 img.height,
124 &levels[..img.mip_count().max(1)],
125 wgpu::TextureFormat::Rgba8Unorm,
126 ))
127}
128
129pub fn upload_cube(
131 device: &wgpu::Device,
132 queue: &wgpu::Queue,
133 label: &str,
134 img: &ImageBuffer,
135) -> Option<wgpu::TextureView> {
136 if img.faces() != 6 {
137 return None;
138 }
139 let levels = decode_levels(img)?;
140 let mips = img.mip_count().max(1);
141 let texture = device.create_texture(&wgpu::TextureDescriptor {
142 label: Some(label),
143 size: wgpu::Extent3d {
144 width: img.width,
145 height: img.height,
146 depth_or_array_layers: 6,
147 },
148 mip_level_count: mips as u32,
149 sample_count: 1,
150 dimension: wgpu::TextureDimension::D2,
151 format: wgpu::TextureFormat::Rgba8Unorm,
152 usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
153 view_formats: &[],
154 });
155 for face in 0..6 {
156 for mip in 0..mips {
157 let (w, h) = ((img.width >> mip).max(1), (img.height >> mip).max(1));
158 queue.write_texture(
159 wgpu::TexelCopyTextureInfo {
160 texture: &texture,
161 mip_level: mip as u32,
162 origin: wgpu::Origin3d {
163 x: 0,
164 y: 0,
165 z: face as u32,
166 },
167 aspect: wgpu::TextureAspect::All,
168 },
169 &levels[face * mips + mip],
170 wgpu::TexelCopyBufferLayout {
171 offset: 0,
172 bytes_per_row: Some(w * 4),
173 rows_per_image: Some(h),
174 },
175 wgpu::Extent3d {
176 width: w,
177 height: h,
178 depth_or_array_layers: 1,
179 },
180 );
181 }
182 }
183 Some(texture.create_view(&wgpu::TextureViewDescriptor {
184 dimension: Some(wgpu::TextureViewDimension::Cube),
185 ..Default::default()
186 }))
187}