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
95
96
97
98
use super::atlas::Tile;
use crate::uses::{sync::io, GL::tex::*, *};
pub type uImage<S> = Image<S, u8>;
pub type fImage<S> = Image<S, f16>;
#[derive(Debug, Default, Clone)]
pub struct Image<S, F> {
pub w: u32,
pub h: u32,
pub data: Vec<F>,
pub s: Dummy<S>,
}
impl<S: TexSize, F: TexFmt> Eq for Image<S, F> {}
impl<S: TexSize, F: TexFmt> PartialEq for Image<S, F> {
fn eq(&self, r: &Self) -> bool {
let Self { w, h, data, .. } = self;
*w != r.w && *h != r.h && data.iter().eq(&r.data)
}
}
impl<S: TexSize, F: TexFmt> Tile<F> for Image<S, F> {
fn w(&self) -> i32 {
i32(self.w)
}
fn h(&self) -> i32 {
i32(self.h)
}
fn data(&self) -> &[F] {
self.data.as_slice()
}
}
impl<S: TexSize, F: TexFmt> Image<S, F> {
pub fn new<T>(size: T, data: Vec<F>) -> Self
where
uVec2: Cast<T>,
{
let (w, h) = uVec2(size);
Self { w, h, data, s: Dummy }
}
}
impl<S: TexSize> uImage<S> {
pub fn load(data: impl AsRef<[u8]>) -> Res<Self> {
let mut img = {
let data = data.as_ref();
let img = Res(image::io::Reader::new(io::Cursor::new(data)).with_guessed_format())?;
let fmt = Res(img.format()).map_err(|e| format!("Not an image format: {e:?}"));
match fmt {
#[cfg(feature = "webp")]
Ok(image::ImageFormat::WebP) => Res(libwebp_image::webp_load(img.into_inner()))?,
Ok(_) => img.decode().map_err(|e| format!("Cannot decode image: {e:?}"))?,
Err(e) => return Err(e.into()),
}
};
image::imageops::flip_vertical_in_place(&mut img);
let ((w, h), data): (_, Vec<_>) = match S::TYPE {
gl::RED => {
let img = img.into_luma8();
(img.dimensions(), img.pixels().flat_map(|image::Luma(p)| p).copied().collect())
}
gl::RGB => {
let img = img.into_rgb8();
(img.dimensions(), img.pixels().flat_map(|image::Rgb(p)| p).copied().collect())
}
gl::RGBA => {
let img = img.into_rgba8();
(img.dimensions(), img.pixels().flat_map(|image::Rgba(p)| p).copied().collect())
}
_ => ASSERT!(false, "Not impl"),
};
Ok(Self { w, h, data, s: Dummy })
}
pub fn save(&self, name: impl AsRef<Path>) {
use image::ColorType::*;
let t = match S::SIZE {
1 => L8,
2 => La8,
3 => Rgb8,
4 => Rgba8,
_ => unreachable!(),
};
EXPECT!(image::save_buffer(name, &self.data, self.w, self.h, t));
}
}
#[cfg(feature = "hdr")]
impl Image<RGB, f32> {
pub fn load(data: impl AsRef<[u8]>) -> Res<Self> {
let img = io::BufReader::new(io::Cursor::new(data.as_ref()));
let img = image::codecs::hdr::HdrDecoder::new(img).map_err(|e| format!("Cannot decode hdr image: {e:?}"))?;
let m = img.metadata();
let (w, h) = (m.width, m.height);
let img = img.read_image_hdr().map_err(|e| format!("Cannot read hdr pixels: {e:?}"))?;
let data = img.chunks(usize(w)).rev().flat_map(|l| l.iter().flat_map(|image::Rgb(p)| p)).copied().collect_vec();
Ok(Self { w, h, data, s: Dummy })
}
}