1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
use super::Texture2dFactory;
use crate::graphics::{
vulkan::{
buffer::CpuBuffer,
texture::{MipmapExtent, TextureImage},
},
Graphics,
};
use anyhow::Result;
use ash::vk;
use image::ImageBuffer;
use std::path::Path;
pub trait TextureLoader {
fn read_texture_file(
&self,
file_path: impl Into<String>,
) -> Result<TextureImage>;
}
impl TextureLoader for Graphics {
fn read_texture_file(
&self,
file_path: impl Into<String>,
) -> Result<TextureImage> {
let path_string = file_path.into();
let mipmaps = read_file_mipmaps(&path_string)?;
let packed_mipmap_data: Vec<&[u8]> = mipmaps
.iter()
.map(|mipmap| mipmap.as_raw() as &[u8])
.collect();
let mut texture = self.create_empty_2d_texture(
path_string,
mipmaps[0].width(),
mipmaps[0].height(),
mipmaps.len() as u32,
)?;
let mut transfer_buffer = CpuBuffer::new(
self.device.clone(),
vk::BufferUsageFlags::TRANSFER_SRC,
)?;
unsafe {
transfer_buffer.write_data_arrays(&packed_mipmap_data)?;
let mipmap_sizes: Vec<MipmapExtent> = mipmaps
.iter()
.map(|mipmap| MipmapExtent {
width: mipmap.width(),
height: mipmap.height(),
})
.collect();
texture
.upload_mipmaps_from_buffer(&transfer_buffer, &mipmap_sizes)?;
}
Ok(texture)
}
}
type ImageBufferU8 = ImageBuffer<image::Rgba<u8>, Vec<u8>>;
fn read_file_mipmaps(path: &impl AsRef<Path>) -> Result<Vec<ImageBufferU8>> {
let image_file = image::open(path)?.into_rgba8();
let (width, height) = (image_file.width(), image_file.height());
let mip_levels = (height.max(width) as f32).log2().floor() as u32 + 1;
let mut mipmaps = Vec::with_capacity(mip_levels as usize);
mipmaps.push(image_file.clone());
for mipmap_level in 1..mip_levels {
use image::imageops;
let mipmap = imageops::resize(
&image_file,
width >> mipmap_level,
height >> mipmap_level,
imageops::FilterType::Gaussian,
);
mipmaps.push(mipmap);
}
Ok(mipmaps)
}