diff options
Diffstat (limited to 'opengl-bindings/src/texture.rs')
| -rw-r--r-- | opengl-bindings/src/texture.rs | 236 | 
1 files changed, 236 insertions, 0 deletions
diff --git a/opengl-bindings/src/texture.rs b/opengl-bindings/src/texture.rs new file mode 100644 index 0000000..1859beb --- /dev/null +++ b/opengl-bindings/src/texture.rs @@ -0,0 +1,236 @@ +use crate::data_types::Dimens; +use crate::CurrentContextWithFns; + +#[derive(Debug)] +pub struct Texture +{ +    texture: crate::sys::types::GLuint, +} + +impl Texture +{ +    #[must_use] +    pub fn new(current_context: &CurrentContextWithFns<'_>) -> Self +    { +        let mut texture = crate::sys::types::GLuint::default(); + +        unsafe { +            current_context.fns().CreateTextures( +                crate::sys::TEXTURE_2D, +                1, +                &raw mut texture, +            ); +        }; + +        Self { texture } +    } + +    pub fn bind_to_texture_unit( +        &self, +        current_context: &CurrentContextWithFns<'_>, +        texture_unit: u32, +    ) +    { +        unsafe { +            current_context +                .fns() +                .BindTextureUnit(texture_unit, self.texture); +        } +    } + +    /// Allocates the texture storage, stores pixel data & generates a mipmap. +    /// +    /// # Errors +    /// Returns `Err` if any value in `size` does not fit into a `i32`. +    pub fn generate( +        &self, +        current_context: &CurrentContextWithFns<'_>, +        size: &Dimens<u32>, +        data: &[u8], +        pixel_data_format: PixelDataFormat, +    ) -> Result<(), GenerateError> +    { +        let size = Dimens::<crate::sys::types::GLsizei> { +            width: size.width.try_into().map_err(|_| { +                GenerateError::SizeWidthValueTooLarge { +                    value: size.width, +                    max_value: crate::sys::types::GLsizei::MAX as u32, +                } +            })?, +            height: size.height.try_into().map_err(|_| { +                GenerateError::SizeHeightValueTooLarge { +                    value: size.height, +                    max_value: crate::sys::types::GLsizei::MAX as u32, +                } +            })?, +        }; + +        self.alloc_image(current_context, pixel_data_format, &size, data); + +        unsafe { +            current_context.fns().GenerateTextureMipmap(self.texture); +        } + +        Ok(()) +    } + +    pub fn set_wrap( +        &self, +        current_context: &CurrentContextWithFns<'_>, +        wrapping: Wrapping, +    ) +    { +        unsafe { +            current_context.fns().TextureParameteri( +                self.texture, +                crate::sys::TEXTURE_WRAP_S, +                wrapping as i32, +            ); + +            current_context.fns().TextureParameteri( +                self.texture, +                crate::sys::TEXTURE_WRAP_T, +                wrapping as i32, +            ); +        } +    } + +    pub fn set_magnifying_filter( +        &self, +        current_context: &CurrentContextWithFns<'_>, +        filtering: Filtering, +    ) +    { +        unsafe { +            current_context.fns().TextureParameteri( +                self.texture, +                crate::sys::TEXTURE_MAG_FILTER, +                filtering as i32, +            ); +        } +    } + +    pub fn set_minifying_filter( +        &self, +        current_context: &CurrentContextWithFns<'_>, +        filtering: Filtering, +    ) +    { +        unsafe { +            current_context.fns().TextureParameteri( +                self.texture, +                crate::sys::TEXTURE_MIN_FILTER, +                filtering as i32, +            ); +        } +    } + +    pub fn delete(self, current_context: &CurrentContextWithFns<'_>) +    { +        unsafe { +            current_context +                .fns() +                .DeleteTextures(1, &raw const self.texture); +        } +    } + +    fn alloc_image( +        &self, +        current_context: &CurrentContextWithFns<'_>, +        pixel_data_format: PixelDataFormat, +        size: &Dimens<crate::sys::types::GLsizei>, +        data: &[u8], +    ) +    { +        unsafe { +            current_context.fns().TextureStorage2D( +                self.texture, +                1, +                pixel_data_format.to_sized_internal_format(), +                size.width, +                size.height, +            ); + +            current_context.fns().TextureSubImage2D( +                self.texture, +                0, +                0, +                0, +                size.width, +                size.height, +                pixel_data_format.to_format(), +                crate::sys::UNSIGNED_BYTE, +                data.as_ptr().cast(), +            ); +        } +    } +} + +const fn try_cast_u32_to_i32(val: u32) -> i32 +{ +    assert!(val <= i32::MAX as u32); + +    val.cast_signed() +} + +/// Texture wrapping. +#[derive(Debug, Clone, Copy)] +#[repr(i32)] +pub enum Wrapping +{ +    Repeat = const { try_cast_u32_to_i32(crate::sys::REPEAT) }, +    MirroredRepeat = const { try_cast_u32_to_i32(crate::sys::MIRRORED_REPEAT) }, +    ClampToEdge = const { try_cast_u32_to_i32(crate::sys::CLAMP_TO_EDGE) }, +    ClampToBorder = const { try_cast_u32_to_i32(crate::sys::CLAMP_TO_BORDER) }, +} + +#[derive(Debug, Clone, Copy)] +#[repr(i32)] +pub enum Filtering +{ +    Nearest = const { try_cast_u32_to_i32(crate::sys::NEAREST) }, +    Linear = const { try_cast_u32_to_i32(crate::sys::LINEAR) }, +} + +/// Texture pixel data format. +#[derive(Debug, Clone, Copy)] +pub enum PixelDataFormat +{ +    Rgb8, +    Rgba8, +} + +impl PixelDataFormat +{ +    fn to_sized_internal_format(self) -> crate::sys::types::GLenum +    { +        match self { +            Self::Rgb8 => crate::sys::RGB8, +            Self::Rgba8 => crate::sys::RGBA8, +        } +    } + +    fn to_format(self) -> crate::sys::types::GLenum +    { +        match self { +            Self::Rgb8 => crate::sys::RGB, +            Self::Rgba8 => crate::sys::RGBA, +        } +    } +} + +/// Error generating texture. +#[derive(Debug, thiserror::Error)] +pub enum GenerateError +{ +    #[error("Size width value ({value}) is too large. Must be < {max_value}")] +    SizeWidthValueTooLarge +    { +        value: u32, max_value: u32 +    }, +    #[error("Size height value ({value}) is too large. Must be < {max_value}")] +    SizeHeightValueTooLarge +    { +        value: u32, max_value: u32 +    }, +}  | 
