use crate::ToGlEnum;
use crate::gl;
use crate::texture;
use crate::texture::GetFormatError;
#[derive(Debug)]
pub enum ImageUnitError {
NoMipmapAtLevel(u32),
LayeringNotSupported(texture::Dimensions),
LayerOutOfBounds(u32),
BadFormatClass(usize, usize),
GetFormat(GetFormatError),
}
impl std::fmt::Display for ImageUnitError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use self::ImageUnitError::*;
let desc = match *self {
NoMipmapAtLevel(level) => write!(f, "No mipmap level {} found", level),
LayeringNotSupported(kind) => write!(f, "Layering is not supported with textures of dimensions {:?}", kind),
LayerOutOfBounds(layer) => write!(f, "Request layer {} is out of bounds", layer),
BadFormatClass(tbits, ibits) => write!(f, "Texture format has {} bits but image format has {} bits", tbits, ibits),
GetFormat(error) => write!(f, "{}", error),
};
Ok(())
}
}
impl std::error::Error for ImageUnitError {}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub struct ImageUnitBehavior {
pub level: u32,
pub(crate) layer: Option<u32>,
pub access: ImageUnitAccess,
pub format: ImageUnitFormat,
}
impl Default for ImageUnitBehavior {
#[inline]
fn default() -> ImageUnitBehavior {
ImageUnitBehavior {
level: 0,
layer: None,
access: ImageUnitAccess::ReadWrite,
format: ImageUnitFormat::R32I,
}
}
}
pub struct ImageUnit<'t, T: 't + core::ops::Deref<Target = crate::texture::TextureAny>>(pub &'t T, pub ImageUnitBehavior);
impl<'t, T: 't + core::ops::Deref<Target = crate::texture::TextureAny>> ImageUnit<'t, T> {
pub fn new(texture: &'t T, format: ImageUnitFormat) -> Result<ImageUnit<'t, T>, ImageUnitError> {
let tbits = texture.get_internal_format().unwrap().get_total_bits();
if tbits != format.get_total_bits() {
return Err(ImageUnitError::BadFormatClass(tbits, format.get_total_bits()))
}
Ok(ImageUnit(texture, ImageUnitBehavior {
format,
..Default::default()
}))
}
pub fn set_level(mut self, level: u32) -> Result<Self, ImageUnitError> {
self.0.mipmap(level).ok_or(ImageUnitError::NoMipmapAtLevel(level))?;
self.1.level = level;
Ok(self)
}
pub fn set_layer(mut self, layer: Option<u32>) -> Result<Self, ImageUnitError> {
if let Some(layer) = layer {
match self.0.dimensions() {
texture::Dimensions::Texture1d { width } =>
Err(ImageUnitError::LayeringNotSupported(self.0.dimensions())),
texture::Dimensions::Texture2d { width, height } =>
Err(ImageUnitError::LayeringNotSupported(self.0.dimensions())),
texture::Dimensions::Texture2dMultisample { width, height, samples } =>
Err(ImageUnitError::LayeringNotSupported(self.0.dimensions())),
texture::Dimensions::Texture1dArray { width, array_size } =>
if layer >= array_size { Err(ImageUnitError::LayerOutOfBounds(layer))} else { Ok(()) },
texture::Dimensions::Texture2dArray { width, height, array_size } =>
if layer >= array_size { Err(ImageUnitError::LayerOutOfBounds(layer))} else { Ok(()) },
texture::Dimensions::Texture2dMultisampleArray { width, height, array_size, samples } =>
if layer >= array_size { Err(ImageUnitError::LayerOutOfBounds(layer))} else { Ok(()) },
texture::Dimensions::Texture3d { width, height, depth } =>
if layer >= depth { Err(ImageUnitError::LayerOutOfBounds(layer))} else { Ok(()) },
texture::Dimensions::Cubemap { dimension } =>
if layer >= 6 { Err(ImageUnitError::LayerOutOfBounds(layer))} else { Ok(()) },
texture::Dimensions::CubemapArray { dimension, array_size } =>
if layer >= 6*array_size { Err(ImageUnitError::LayerOutOfBounds(layer))} else { Ok(()) },
}?;
}
self.1.layer = layer;
Ok(self)
}
pub fn set_access(mut self, access: ImageUnitAccess) -> Self {
self.1.access = access;
self
}
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum ImageUnitAccess {
Read,
Write,
ReadWrite,
}
impl ToGlEnum for ImageUnitAccess {
#[inline]
fn to_glenum(&self) -> gl::types::GLenum {
match *self {
ImageUnitAccess::Read => gl::READ_ONLY,
ImageUnitAccess::Write => gl::WRITE_ONLY,
ImageUnitAccess::ReadWrite => gl::READ_WRITE,
}
}
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum ImageUnitFormat {
RGBA32F,
RGBA16F,
RG32F,
RG16F,
R11FG11FB10F,
R32F,
R16F,
RGBA32UI,
RGBA16UI,
RGB10A2UI,
RGBA8UI,
RG32UI,
RG16UI,
RG8UI,
R32UI,
R16UI,
R8UI,
RGBA32I,
RGBA16I,
RGBA8I,
RG32I,
RG16I,
RG8I,
R32I,
R16I,
R8I,
RGBA16,
RGB10A2,
RGBA8,
RG16,
RG8,
R16,
R8,
RGBA16snorm,
RGBA8snorm,
RG16snorm,
RG8snorm,
R16snorm,
R8snorm,
}
impl ImageUnitFormat {
fn get_total_bits(&self) -> usize {
match self {
ImageUnitFormat::RGBA32F => 4*32,
ImageUnitFormat::RGBA16F => 4*16,
ImageUnitFormat::RG32F => 2*32,
ImageUnitFormat::RG16F => 2*16,
ImageUnitFormat::R11FG11FB10F => 11*2 + 10,
ImageUnitFormat::R32F => 1*32,
ImageUnitFormat::R16F => 1*16,
ImageUnitFormat::RGBA32UI => 4*32,
ImageUnitFormat::RGBA16UI => 4*16,
ImageUnitFormat::RGB10A2UI => 3*10 + 2,
ImageUnitFormat::RGBA8UI => 8*4,
ImageUnitFormat::RG32UI => 2*32,
ImageUnitFormat::RG16UI => 2*16,
ImageUnitFormat::RG8UI => 2*8,
ImageUnitFormat::R32UI => 1*32,
ImageUnitFormat::R16UI => 1*16,
ImageUnitFormat::R8UI => 1*8,
ImageUnitFormat::RGBA32I => 4*32,
ImageUnitFormat::RGBA16I => 2*32,
ImageUnitFormat::RGBA8I => 4*8,
ImageUnitFormat::RG32I => 2*32,
ImageUnitFormat::RG16I => 2*16,
ImageUnitFormat::RG8I => 2*8,
ImageUnitFormat::R32I => 1*32,
ImageUnitFormat::R16I => 1*16,
ImageUnitFormat::R8I => 1*8,
ImageUnitFormat::RGBA16 => 4*16,
ImageUnitFormat::RGB10A2 => 3*10+2,
ImageUnitFormat::RGBA8 => 4*8,
ImageUnitFormat::RG16 => 2*16,
ImageUnitFormat::RG8 => 2*8,
ImageUnitFormat::R16 => 1*16,
ImageUnitFormat::R8 => 1*8,
ImageUnitFormat::RGBA16snorm => 4*16,
ImageUnitFormat::RGBA8snorm => 4*8,
ImageUnitFormat::RG16snorm => 2*16,
ImageUnitFormat::RG8snorm => 2*8,
ImageUnitFormat::R16snorm => 1*16,
ImageUnitFormat::R8snorm => 1*8,
}
}
}
impl ToGlEnum for ImageUnitFormat {
#[inline]
fn to_glenum(&self) -> gl::types::GLenum {
match *self {
ImageUnitFormat::RGBA32F => gl::RGBA32F,
ImageUnitFormat::RGBA16F => gl::RGBA16F,
ImageUnitFormat::RG32F => gl::RG32F,
ImageUnitFormat::RG16F => gl::RG16F,
ImageUnitFormat::R11FG11FB10F => gl::R11F_G11F_B10F,
ImageUnitFormat::R32F => gl::R32F,
ImageUnitFormat::R16F => gl::R16F,
ImageUnitFormat::RGBA32UI => gl::RGBA32UI,
ImageUnitFormat::RGBA16UI => gl::RGBA16UI,
ImageUnitFormat::RGB10A2UI => gl::RGB10_A2UI,
ImageUnitFormat::RGBA8UI => gl::RGBA8UI,
ImageUnitFormat::RG32UI => gl::RG32UI,
ImageUnitFormat::RG16UI => gl::RG16UI,
ImageUnitFormat::RG8UI => gl::RG8UI,
ImageUnitFormat::R32UI => gl::R32UI,
ImageUnitFormat::R16UI => gl::R16UI,
ImageUnitFormat::R8UI => gl::R8UI,
ImageUnitFormat::RGBA32I => gl::RGBA32I,
ImageUnitFormat::RGBA16I => gl::RGBA16I,
ImageUnitFormat::RGBA8I => gl::RGBA8I,
ImageUnitFormat::RG32I => gl::RG32I,
ImageUnitFormat::RG16I => gl::RG16I,
ImageUnitFormat::RG8I => gl::RG8I,
ImageUnitFormat::R32I => gl::R32I,
ImageUnitFormat::R16I => gl::R16I,
ImageUnitFormat::R8I => gl::R8I,
ImageUnitFormat::RGBA16 => gl::RGBA16,
ImageUnitFormat::RGB10A2 => gl::RGB10_A2,
ImageUnitFormat::RGBA8 => gl::RGBA8,
ImageUnitFormat::RG16 => gl::RG16,
ImageUnitFormat::RG8 => gl::RG8,
ImageUnitFormat::R16 => gl::R16,
ImageUnitFormat::R8 => gl::R8,
ImageUnitFormat::RGBA16snorm => gl::RGBA16_SNORM,
ImageUnitFormat::RGBA8snorm => gl::RGBA8_SNORM,
ImageUnitFormat::RG16snorm => gl::RG16_SNORM,
ImageUnitFormat::RG8snorm => gl::RG8_SNORM,
ImageUnitFormat::R16snorm => gl::R16_SNORM,
ImageUnitFormat::R8snorm => gl::R8_SNORM,
}
}
}