use crate::opengl::currently_bound::CurrentlyBound; use crate::vector::Vec2; #[derive(Debug)] pub struct Texture { texture: gl::types::GLuint, } impl Texture { pub fn new() -> Self { let mut texture = gl::types::GLuint::default(); unsafe { gl::GenTextures(1, &mut texture); }; Self { texture } } pub fn bind(&self, cb: impl FnOnce(CurrentlyBound<'_, Self>)) { unsafe { gl::BindTexture(gl::TEXTURE_2D, self.texture); } // SAFETY: The buffer object is bound above let currently_bound = unsafe { CurrentlyBound::new() }; cb(currently_bound); } pub fn generate( _: &CurrentlyBound, dimens: &Vec2, data: &[u8], pixel_data_format: PixelDataFormat, ) { #[allow(clippy::cast_possible_wrap)] unsafe { gl::TexImage2D( gl::TEXTURE_2D, 0, pixel_data_format.to_gl() as i32, dimens.x as i32, dimens.y as i32, 0, pixel_data_format.to_gl(), gl::UNSIGNED_BYTE, data.as_ptr().cast(), ); gl::GenerateMipmap(gl::TEXTURE_2D); } } pub fn set_wrap(_: CurrentlyBound, wrapping: Wrapping) { let wrapping_gl = wrapping.to_gl(); #[allow(clippy::cast_possible_wrap)] unsafe { gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, wrapping_gl as i32); gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, wrapping_gl as i32); } } pub fn set_magnifying_filter(_: CurrentlyBound, filtering: Filtering) { let filtering_gl = filtering.to_gl(); #[allow(clippy::cast_possible_wrap)] unsafe { gl::TexParameteri( gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, filtering_gl as i32, ); } } pub fn set_minifying_filter(_: CurrentlyBound, filtering: Filtering) { let filtering_gl = filtering.to_gl(); #[allow(clippy::cast_possible_wrap)] unsafe { gl::TexParameteri( gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, filtering_gl as i32, ); } } } impl Drop for Texture { fn drop(&mut self) { unsafe { gl::DeleteTextures(1, &self.texture); } } } /// Texture wrapping. #[derive(Debug, Clone, Copy)] pub enum Wrapping { Repeat, MirroredRepeat, ClampToEdge, ClampToBorder, } impl Wrapping { fn to_gl(self) -> gl::types::GLenum { match self { Self::Repeat => gl::REPEAT, Self::MirroredRepeat => gl::MIRRORED_REPEAT, Self::ClampToEdge => gl::CLAMP_TO_EDGE, Self::ClampToBorder => gl::CLAMP_TO_BORDER, } } } #[derive(Debug, Clone, Copy)] pub enum Filtering { Nearest, Linear, } impl Filtering { fn to_gl(self) -> gl::types::GLenum { match self { Self::Linear => gl::LINEAR, Self::Nearest => gl::NEAREST, } } } /// Texture pixel data format. #[derive(Debug, Clone, Copy)] pub enum PixelDataFormat { Rgb, Rgba, } impl PixelDataFormat { fn to_gl(self) -> gl::types::GLenum { match self { Self::Rgb => gl::RGB, Self::Rgba => gl::RGBA, } } }