use crate::data_types::dimens::Dimens; use crate::texture::{Id, Properties}; #[derive(Debug)] pub struct Texture { texture: gl::types::GLuint, } impl Texture { pub fn new() -> Self { let mut texture = gl::types::GLuint::default(); unsafe { gl::CreateTextures(gl::TEXTURE_2D, 1, &mut texture); }; Self { texture } } pub fn bind(&self) { unsafe { gl::BindTexture(gl::TEXTURE_2D, self.texture); } } pub fn generate( &mut self, dimens: Dimens, data: &[u8], pixel_data_format: PixelDataFormat, ) { self.alloc_image(pixel_data_format, dimens, data); unsafe { gl::GenerateTextureMipmap(self.texture); } } pub fn apply_properties(&mut self, properties: &Properties) { self.set_wrap(properties.wrap); self.set_magnifying_filter(properties.magnifying_filter); self.set_minifying_filter(properties.minifying_filter); } pub fn set_wrap(&mut self, wrapping: Wrapping) { let wrapping_gl = wrapping.to_gl(); #[allow(clippy::cast_possible_wrap)] unsafe { gl::TextureParameteri(self.texture, gl::TEXTURE_WRAP_S, wrapping_gl as i32); gl::TextureParameteri(self.texture, gl::TEXTURE_WRAP_T, wrapping_gl as i32); } } pub fn set_magnifying_filter(&mut self, filtering: Filtering) { let filtering_gl = filtering.to_gl(); #[allow(clippy::cast_possible_wrap)] unsafe { gl::TextureParameteri( self.texture, gl::TEXTURE_MAG_FILTER, filtering_gl as i32, ); } } pub fn set_minifying_filter(&mut self, filtering: Filtering) { let filtering_gl = filtering.to_gl(); #[allow(clippy::cast_possible_wrap)] unsafe { gl::TextureParameteri( self.texture, gl::TEXTURE_MIN_FILTER, filtering_gl as i32, ); } } fn alloc_image( &mut self, pixel_data_format: PixelDataFormat, dimens: Dimens, data: &[u8], ) { unsafe { #[allow(clippy::cast_possible_wrap)] gl::TextureStorage2D( self.texture, 1, pixel_data_format.to_sized_internal_format(), dimens.width as i32, dimens.height as i32, ); #[allow(clippy::cast_possible_wrap)] gl::TextureSubImage2D( self.texture, 0, 0, 0, dimens.width as i32, dimens.height as i32, pixel_data_format.to_format(), gl::UNSIGNED_BYTE, data.as_ptr().cast(), ); } } } 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 { Rgb8, Rgba8, } impl PixelDataFormat { fn to_sized_internal_format(self) -> gl::types::GLenum { match self { Self::Rgb8 => gl::RGB8, Self::Rgba8 => gl::RGBA8, } } fn to_format(self) -> gl::types::GLenum { match self { Self::Rgb8 => gl::RGB, Self::Rgba8 => gl::RGBA, } } } pub fn set_active_texture_unit(texture_unit: TextureUnit) { unsafe { gl::ActiveTexture(texture_unit.into_gl()); } } macro_rules! texture_unit_enum { (cnt=$cnt: literal) => { seq_macro::seq!(N in 0..$cnt { #[derive(Debug, Clone, Copy)] pub enum TextureUnit { #( No~N, )* } impl TextureUnit { fn into_gl(self) -> gl::types::GLenum { match self { #( Self::No~N => gl::TEXTURE~N, )* } } pub fn from_texture_id(texture_id: Id) -> Option { match texture_id.into_inner() { #( N => Some(Self::No~N), )* _ => None } } } }); }; } texture_unit_enum!(cnt = 31);