1use crate::ToGlEnum;
3use crate::gl;
4use crate::texture;
5use crate::texture::GetFormatError;
6
7#[derive(Debug)]
8pub enum ImageUnitError {
10 NoMipmapAtLevel(u32),
12 LayeringNotSupported(texture::Dimensions),
14 LayerOutOfBounds(u32),
16 BadFormatClass(usize, usize),
18 GetFormat(GetFormatError),
20}
21
22impl std::fmt::Display for ImageUnitError {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 use self::ImageUnitError::*;
25
26 let desc = match *self {
27 NoMipmapAtLevel(level) => write!(f, "No mipmap level {} found", level),
28 LayeringNotSupported(kind) => write!(f, "Layering is not supported with textures of dimensions {:?}", kind),
29 LayerOutOfBounds(layer) => write!(f, "Request layer {} is out of bounds", layer),
30 BadFormatClass(tbits, ibits) => write!(f, "Texture format has {} bits but image format has {} bits", tbits, ibits),
31 GetFormat(error) => write!(f, "{}", error),
32 };
33 Ok(())
34 }
35}
36
37impl std::error::Error for ImageUnitError {}
38
39
40#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
42pub struct ImageUnitBehavior {
43 pub level: u32,
45 pub(crate) layer: Option<u32>,
46 pub access: ImageUnitAccess,
48 pub format: ImageUnitFormat,
50}
51
52impl Default for ImageUnitBehavior {
53 #[inline]
54 fn default() -> ImageUnitBehavior {
55 ImageUnitBehavior {
56 level: 0,
57 layer: None,
58 access: ImageUnitAccess::ReadWrite,
59 format: ImageUnitFormat::R32I,
60 }
61 }
62}
63
64pub struct ImageUnit<'t, T: 't + core::ops::Deref<Target = crate::texture::TextureAny>>(pub &'t T, pub ImageUnitBehavior);
66
67impl<'t, T: 't + core::ops::Deref<Target = crate::texture::TextureAny>> ImageUnit<'t, T> {
68 pub fn new(texture: &'t T, format: ImageUnitFormat) -> Result<ImageUnit<'t, T>, ImageUnitError> {
70 let tbits = texture.get_internal_format().unwrap().get_total_bits();
71 if tbits != format.get_total_bits() {
72 return Err(ImageUnitError::BadFormatClass(tbits, format.get_total_bits()))
73 }
74
75 Ok(ImageUnit(texture, ImageUnitBehavior {
76 format,
77 ..Default::default()
78 }))
79 }
80
81 pub fn set_level(mut self, level: u32) -> Result<Self, ImageUnitError> {
83 self.0.mipmap(level).ok_or(ImageUnitError::NoMipmapAtLevel(level))?;
84 self.1.level = level;
85 Ok(self)
86 }
87
88 pub fn set_layer(mut self, layer: Option<u32>) -> Result<Self, ImageUnitError> {
91 if let Some(layer) = layer {
92 match self.0.dimensions() {
93 texture::Dimensions::Texture1d { width } =>
94 Err(ImageUnitError::LayeringNotSupported(self.0.dimensions())),
95 texture::Dimensions::Texture2d { width, height } =>
96 Err(ImageUnitError::LayeringNotSupported(self.0.dimensions())),
97 texture::Dimensions::Texture2dMultisample { width, height, samples } =>
98 Err(ImageUnitError::LayeringNotSupported(self.0.dimensions())),
99 texture::Dimensions::Texture1dArray { width, array_size } =>
100 if layer >= array_size { Err(ImageUnitError::LayerOutOfBounds(layer))} else { Ok(()) },
101 texture::Dimensions::Texture2dArray { width, height, array_size } =>
102 if layer >= array_size { Err(ImageUnitError::LayerOutOfBounds(layer))} else { Ok(()) },
103 texture::Dimensions::Texture2dMultisampleArray { width, height, array_size, samples } =>
104 if layer >= array_size { Err(ImageUnitError::LayerOutOfBounds(layer))} else { Ok(()) },
105 texture::Dimensions::Texture3d { width, height, depth } =>
106 if layer >= depth { Err(ImageUnitError::LayerOutOfBounds(layer))} else { Ok(()) },
107 texture::Dimensions::Cubemap { dimension } =>
108 if layer >= 6 { Err(ImageUnitError::LayerOutOfBounds(layer))} else { Ok(()) },
109 texture::Dimensions::CubemapArray { dimension, array_size } =>
110 if layer >= 6*array_size { Err(ImageUnitError::LayerOutOfBounds(layer))} else { Ok(()) },
111 }?;
112 }
113 self.1.layer = layer;
114 Ok(self)
115 }
116
117 pub fn set_access(mut self, access: ImageUnitAccess) -> Self {
119 self.1.access = access;
120 self
121 }
122
123}
124
125#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
127pub enum ImageUnitAccess {
128 Read,
130 Write,
132 ReadWrite,
134}
135
136impl ToGlEnum for ImageUnitAccess {
137 #[inline]
138 fn to_glenum(&self) -> gl::types::GLenum {
139 match *self {
140 ImageUnitAccess::Read => gl::READ_ONLY,
141 ImageUnitAccess::Write => gl::WRITE_ONLY,
142 ImageUnitAccess::ReadWrite => gl::READ_WRITE,
143 }
144 }
145}
146
147
148
149#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
151pub enum ImageUnitFormat {
152 RGBA32F,
154 RGBA16F,
156 RG32F,
158 RG16F,
160 R11FG11FB10F,
162 R32F,
164 R16F,
166
167 RGBA32UI,
169 RGBA16UI,
171 RGB10A2UI,
173 RGBA8UI,
175 RG32UI,
177 RG16UI,
179 RG8UI,
181 R32UI,
183 R16UI,
185 R8UI,
187
188 RGBA32I,
190 RGBA16I,
192 RGBA8I,
194 RG32I,
196 RG16I,
198 RG8I,
200 R32I,
202 R16I,
204 R8I,
206
207 RGBA16,
209 RGB10A2,
211 RGBA8,
213 RG16,
215 RG8,
217 R16,
219 R8,
221
222 RGBA16snorm,
224 RGBA8snorm,
226 RG16snorm,
228 RG8snorm,
230 R16snorm,
232 R8snorm,
234}
235
236impl ImageUnitFormat {
237 fn get_total_bits(&self) -> usize {
238 match self {
239 ImageUnitFormat::RGBA32F => 4*32,
240 ImageUnitFormat::RGBA16F => 4*16,
241 ImageUnitFormat::RG32F => 2*32,
242 ImageUnitFormat::RG16F => 2*16,
243 ImageUnitFormat::R11FG11FB10F => 11*2 + 10,
244 ImageUnitFormat::R32F => 1*32,
245 ImageUnitFormat::R16F => 1*16,
246
247 ImageUnitFormat::RGBA32UI => 4*32,
248 ImageUnitFormat::RGBA16UI => 4*16,
249 ImageUnitFormat::RGB10A2UI => 3*10 + 2,
250 ImageUnitFormat::RGBA8UI => 8*4,
251 ImageUnitFormat::RG32UI => 2*32,
252 ImageUnitFormat::RG16UI => 2*16,
253 ImageUnitFormat::RG8UI => 2*8,
254 ImageUnitFormat::R32UI => 1*32,
255 ImageUnitFormat::R16UI => 1*16,
256 ImageUnitFormat::R8UI => 1*8,
257
258 ImageUnitFormat::RGBA32I => 4*32,
259 ImageUnitFormat::RGBA16I => 2*32,
260 ImageUnitFormat::RGBA8I => 4*8,
261 ImageUnitFormat::RG32I => 2*32,
262 ImageUnitFormat::RG16I => 2*16,
263 ImageUnitFormat::RG8I => 2*8,
264 ImageUnitFormat::R32I => 1*32,
265 ImageUnitFormat::R16I => 1*16,
266 ImageUnitFormat::R8I => 1*8,
267
268 ImageUnitFormat::RGBA16 => 4*16,
269 ImageUnitFormat::RGB10A2 => 3*10+2,
270 ImageUnitFormat::RGBA8 => 4*8,
271 ImageUnitFormat::RG16 => 2*16,
272 ImageUnitFormat::RG8 => 2*8,
273 ImageUnitFormat::R16 => 1*16,
274 ImageUnitFormat::R8 => 1*8,
275
276 ImageUnitFormat::RGBA16snorm => 4*16,
277 ImageUnitFormat::RGBA8snorm => 4*8,
278 ImageUnitFormat::RG16snorm => 2*16,
279 ImageUnitFormat::RG8snorm => 2*8,
280 ImageUnitFormat::R16snorm => 1*16,
281 ImageUnitFormat::R8snorm => 1*8,
282 }
283 }
284}
285
286impl ToGlEnum for ImageUnitFormat {
287 #[inline]
288 fn to_glenum(&self) -> gl::types::GLenum {
289 match *self {
290 ImageUnitFormat::RGBA32F => gl::RGBA32F,
291 ImageUnitFormat::RGBA16F => gl::RGBA16F,
292 ImageUnitFormat::RG32F => gl::RG32F,
293 ImageUnitFormat::RG16F => gl::RG16F,
294 ImageUnitFormat::R11FG11FB10F => gl::R11F_G11F_B10F,
295 ImageUnitFormat::R32F => gl::R32F,
296 ImageUnitFormat::R16F => gl::R16F,
297
298 ImageUnitFormat::RGBA32UI => gl::RGBA32UI,
299 ImageUnitFormat::RGBA16UI => gl::RGBA16UI,
300 ImageUnitFormat::RGB10A2UI => gl::RGB10_A2UI,
301 ImageUnitFormat::RGBA8UI => gl::RGBA8UI,
302 ImageUnitFormat::RG32UI => gl::RG32UI,
303 ImageUnitFormat::RG16UI => gl::RG16UI,
304 ImageUnitFormat::RG8UI => gl::RG8UI,
305 ImageUnitFormat::R32UI => gl::R32UI,
306 ImageUnitFormat::R16UI => gl::R16UI,
307 ImageUnitFormat::R8UI => gl::R8UI,
308
309 ImageUnitFormat::RGBA32I => gl::RGBA32I,
310 ImageUnitFormat::RGBA16I => gl::RGBA16I,
311 ImageUnitFormat::RGBA8I => gl::RGBA8I,
312 ImageUnitFormat::RG32I => gl::RG32I,
313 ImageUnitFormat::RG16I => gl::RG16I,
314 ImageUnitFormat::RG8I => gl::RG8I,
315 ImageUnitFormat::R32I => gl::R32I,
316 ImageUnitFormat::R16I => gl::R16I,
317 ImageUnitFormat::R8I => gl::R8I,
318
319 ImageUnitFormat::RGBA16 => gl::RGBA16,
320 ImageUnitFormat::RGB10A2 => gl::RGB10_A2,
321 ImageUnitFormat::RGBA8 => gl::RGBA8,
322 ImageUnitFormat::RG16 => gl::RG16,
323 ImageUnitFormat::RG8 => gl::RG8,
324 ImageUnitFormat::R16 => gl::R16,
325 ImageUnitFormat::R8 => gl::R8,
326
327 ImageUnitFormat::RGBA16snorm => gl::RGBA16_SNORM,
328 ImageUnitFormat::RGBA8snorm => gl::RGBA8_SNORM,
329 ImageUnitFormat::RG16snorm => gl::RG16_SNORM,
330 ImageUnitFormat::RG8snorm => gl::RG8_SNORM,
331 ImageUnitFormat::R16snorm => gl::R16_SNORM,
332 ImageUnitFormat::R8snorm => gl::R8_SNORM,
333 }
334 }
335}
336