1pub use image::ImageError;
2use librashader_common::Size;
3use std::marker::PhantomData;
4
5use image::error::{LimitError, LimitErrorKind};
6use image::DynamicImage;
7use librashader_pack::{TextureBuffer, TextureResource};
8use librashader_presets::TextureMeta;
9use std::path::Path;
10
11pub struct Image<P: PixelFormat = RGBA8> {
13 pub bytes: Vec<u8>,
15 pub size: Size<u32>,
17 pub pitch: usize,
19 _pd: PhantomData<P>,
20}
21
22pub struct RGBA8;
26
27pub struct BGRA8;
31
32pub struct ARGB8;
36
37pub trait PixelFormat {
39 #[doc(hidden)]
40 fn convert(pixels: &mut Vec<u8>);
41}
42
43impl PixelFormat for RGBA8 {
44 fn convert(_pixels: &mut Vec<u8>) {}
45}
46
47impl PixelFormat for BGRA8 {
48 fn convert(pixels: &mut Vec<u8>) {
49 const BGRA_SWIZZLE: &[usize; 32] = &generate_swizzle([2, 1, 0, 3]);
50 swizzle_pixels(pixels, BGRA_SWIZZLE);
51 }
52}
53
54impl PixelFormat for ARGB8 {
55 fn convert(pixels: &mut Vec<u8>) {
56 const ARGB_SWIZZLE: &[usize; 32] = &generate_swizzle([3, 0, 1, 2]);
57 swizzle_pixels(pixels, ARGB_SWIZZLE);
58 }
59}
60
61#[derive(Copy, Clone, Debug, Eq, PartialEq)]
63pub enum UVDirection {
64 TopLeft,
66 BottomLeft,
68}
69
70impl<P: PixelFormat> Image<P> {
71 pub fn load(path: impl AsRef<Path>, direction: UVDirection) -> Result<Self, ImageError> {
73 let image = image::open(path.as_ref())?;
74 Ok(Self::convert(image, direction))
75 }
76
77 pub fn load_from_buffer(
79 buffer: TextureBuffer,
80 direction: UVDirection,
81 ) -> Result<Self, ImageError> {
82 let Some(image) = buffer.into() else {
83 return Err(ImageError::Limits(LimitError::from_kind(
84 LimitErrorKind::InsufficientMemory,
85 )));
86 };
87 let image = DynamicImage::ImageRgba8(image);
88 Ok(Self::convert(image, direction))
89 }
90
91 fn convert(mut image: DynamicImage, direction: UVDirection) -> Self {
92 if direction == UVDirection::BottomLeft {
93 image = image.flipv();
94 }
95
96 let image = if let DynamicImage::ImageRgba8(image) = image {
97 image
98 } else {
99 image.to_rgba8()
100 };
101
102 let height = image.height();
103 let width = image.width();
104 let pitch = image
105 .sample_layout()
106 .height_stride
107 .max(image.sample_layout().width_stride);
108
109 let mut bytes = image.into_raw();
110 P::convert(&mut bytes);
111 Image {
112 bytes,
113 pitch,
114 size: Size { height, width },
115 _pd: Default::default(),
116 }
117 }
118}
119
120pub struct LoadedTexture<P: PixelFormat = RGBA8> {
122 pub image: Image<P>,
124 pub meta: TextureMeta,
126}
127
128impl<P: PixelFormat> LoadedTexture<P> {
129 pub fn from_texture(
131 texture: TextureResource,
132 direction: UVDirection,
133 ) -> Result<Self, ImageError> {
134 Ok(LoadedTexture {
135 meta: texture.meta,
136 image: Image::load_from_buffer(texture.data, direction)?,
137 })
138 }
139}
140
141#[inline(always)]
143fn swizzle_pixels(pixels: &mut Vec<u8>, swizzle: &'static [usize; 32]) {
144 assert!(pixels.len() % 4 == 0);
145 let mut chunks = pixels.chunks_exact_mut(32);
146
147 for chunk in &mut chunks {
149 let tmp = swizzle.map(|i| chunk[i]);
150 chunk.copy_from_slice(&tmp[..])
151 }
152
153 let remainder = chunks.into_remainder();
154 for chunk in remainder.chunks_exact_mut(4) {
155 let argb = [
156 chunk[swizzle[0]],
157 chunk[swizzle[1]],
158 chunk[swizzle[2]],
159 chunk[swizzle[3]],
160 ];
161 chunk.copy_from_slice(&argb[..])
162 }
163}
164
165const fn generate_swizzle<const LEN: usize>(swizzle: [usize; 4]) -> [usize; LEN] {
166 assert!(LEN % 4 == 0, "length of swizzle must be divisible by 4");
167 let mut out: [usize; LEN] = [0; LEN];
168
169 let mut index = 0;
170 while index < LEN {
171 let chunk = [index, index + 1, index + 2, index + 3];
172 out[index + 0] = chunk[swizzle[0]];
173 out[index + 1] = chunk[swizzle[1]];
174 out[index + 2] = chunk[swizzle[2]];
175 out[index + 3] = chunk[swizzle[3]];
176
177 index += 4;
178 }
179
180 out
181}
182
183#[cfg(test)]
184mod test {
185 use crate::image::generate_swizzle;
186
187 #[test]
188 pub fn generate_normal_swizzle() {
189 let swizzle = generate_swizzle::<32>([0, 1, 2, 3]);
190 #[rustfmt::skip]
191 let expected = [
192 0, 1, 2, 3,
193 4, 5, 6, 7,
194 8, 9, 10, 11,
195 12, 13, 14, 15,
196 16, 17, 18, 19,
197 20, 21, 22, 23,
198 24, 25, 26, 27,
199 28, 29, 30, 31
200 ];
201 assert_eq!(swizzle, expected)
202 }
203
204 #[test]
205 pub fn generate_argb_swizzle() {
206 let swizzle = generate_swizzle::<32>([3, 0, 1, 2]);
207 #[rustfmt::skip]
208 let expected = [
209 3, 0, 1, 2,
210 7, 4, 5, 6,
211 11, 8, 9, 10,
212 15, 12, 13, 14,
213 19, 16, 17, 18,
214 23, 20, 21, 22,
215 27, 24, 25, 26,
216 31, 28, 29, 30
217 ];
218 assert_eq!(swizzle, expected)
219 }
220}