use std::fs::File; use std::io::{Read, Seek}; use std::path::Path; use imagefmt::{read_from, ColFmt, Error as ImageFmtError}; use crate::{ error::Error, misc::{AsEnum, BindGuard, Bindable}, }; /* Texture */ pub struct Texture { id: gl::GLuint, target: Target, filter_min: FilterMin, filter_mag: FilterMag, wrap_s: Wrap, wrap_t: Wrap, wrap_r: Wrap, } impl Texture { pub fn new(target: Target) -> Result { let mut id = 0; Error::checked(|| gl::create_textures(target.as_enum(), 1, &mut id))?; Ok(Self { id, target, filter_min: FilterMin::Nearest, filter_mag: FilterMag::Nearest, wrap_s: Wrap::Repeat, wrap_t: Wrap::Repeat, wrap_r: Wrap::Repeat, }) } pub fn id(&self) -> gl::GLuint { self.id } pub fn upload(&mut self, data: &Data, generate_mipmap: bool) -> Result<(), Error> { let info = data.format.info(); if info.gl_format == 0 || info.gl_format_data == 0 || info.gl_format_internal == 0 { return Err(Error::TextureUnsupportedFormat); } let target = self.target.as_enum(); let _guard = BindGuard::new(&*self); Error::checked(|| { gl::tex_image_2d( target, 0, info.gl_format_internal as gl::GLint, data.width as gl::GLint, data.height as gl::GLint, 0, info.gl_format, info.gl_format_data, data.buffer.as_ptr() as *const _, ) })?; if generate_mipmap { Error::checked(|| gl::generate_mipmap(target))?; } self.setup() } pub fn set_filter(&mut self, min: FilterMin, mag: FilterMag) -> Result<(), Error> { self.filter_min = min; self.filter_mag = mag; self.setup() } pub fn set_wrap(&mut self, s: Wrap, t: Wrap, r: Wrap) -> Result<(), Error> { self.wrap_s = s; self.wrap_t = t; self.wrap_r = r; self.setup() } fn setup(&self) -> Result<(), Error> { Error::checked(|| { gl::texture_parameter_i( self.id, gl::TEXTURE_MIN_FILTER, self.filter_min.as_enum() as gl::GLint, ) })?; Error::checked(|| { gl::texture_parameter_i( self.id, gl::TEXTURE_MAG_FILTER, self.filter_mag.as_enum() as gl::GLint, ) })?; Error::checked(|| { gl::texture_parameter_i( self.id, gl::TEXTURE_WRAP_S, self.wrap_s.as_enum() as gl::GLint, ) })?; Error::checked(|| { gl::texture_parameter_i( self.id, gl::TEXTURE_WRAP_T, self.wrap_t.as_enum() as gl::GLint, ) })?; Error::checked(|| { gl::texture_parameter_i( self.id, gl::TEXTURE_WRAP_R, self.wrap_r.as_enum() as gl::GLint, ) })?; Ok(()) } } impl Drop for Texture { fn drop(&mut self) { gl::delete_textures(1, &self.id); } } impl Bindable for Texture { fn bind(&self) { gl::bind_texture(self.target.as_enum(), self.id); } fn unbind(&self) { gl::bind_texture(self.target.as_enum(), 0); } } /* Data */ #[derive(Clone, Debug)] pub struct Data { width: usize, height: usize, format: Format, buffer: Vec, } impl Data { pub fn from_parts(width: usize, height: usize, format: Format, buffer: Vec) -> Self { Self { width, height, format, buffer, } } pub fn from_reader(reader: &mut R) -> Result where R: Read + Seek, { let image = read_from(reader, ColFmt::Auto)?; Ok(Self { width: image.w, height: image.h, format: match image.fmt { ColFmt::Y => Format::Luminance8ub1, ColFmt::YA => Format::Luminance8Alpha8ub2, ColFmt::AY => Format::Alpha8Luminance8ub2, ColFmt::RGB => Format::RGB8ub3, ColFmt::RGBA => Format::RGBA8ub4, ColFmt::BGR => Format::BGR8ub3, ColFmt::BGRA => Format::BGRA8ub4, ColFmt::ARGB => Format::ARGB8ub4, ColFmt::ABGR => Format::ABGR8ub4, ColFmt::Auto => { return Err(ImageFmtError::Internal("Unexpected Format: Auto").into()) } }, buffer: image.buf, }) } pub fn from_file

(path: P) -> Result where P: AsRef, { let mut file = File::open(path)?; Self::from_reader(&mut file) } pub fn format(&self) -> Format { self.format } pub fn width(&self) -> usize { self.width } pub fn height(&self) -> usize { self.height } pub fn convert(&mut self, format: Format, func: F) -> Result<(), Error> where F: Fn(usize, usize, &mut PixelData), { let dst_info = format.info(); let mut dst_descriptor = format.descriptor(); let mut src_descriptor = self.format.descriptor(); let mut tmp = Vec::with_capacity(self.width * self.height * dst_info.bits_per_pixel / 8); let mut src = self.buffer.as_slice(); let mut dst = tmp.as_mut_slice(); let mut data = PixelData::default(); for x in 0..self.width { for y in 0..self.height { let b = src_descriptor.unmap(&mut data, src)?; src = &src[b..]; func(x, y, &mut data); let b = dst_descriptor.map(&data, dst)?; dst = &mut dst[b..]; } } self.buffer = tmp; Ok(()) } pub fn convert_to(&mut self, format: Format) -> Result<(), Error> { if format == self.format { return Ok(()); } if self.format.is_bit_equal(&format) { self.format = format; return Ok(()); } let dst_info = format.info(); let src_info = self.format.info(); if src_info.same_size_channels(&dst_info) { self.convert(format, |_, _, _| {}) } else { self.convert(format, |_, _, data| { data.r = data.r.map(|x| x * dst_info.r_max / src_info.r_max); data.g = data.g.map(|x| x * dst_info.g_max / src_info.g_max); data.b = data.b.map(|x| x * dst_info.b_max / src_info.b_max); data.a = data.a.map(|x| x * dst_info.a_max / src_info.a_max); }) } } } /* FormatDescriptor */ pub trait FormatDescriptor { fn map(&mut self, data: &PixelData, buf: &mut [u8]) -> Result; fn unmap(&mut self, data: &mut PixelData, buf: &[u8]) -> Result; } struct Luminance8ub1Descriptor; impl FormatDescriptor for Luminance8ub1Descriptor { fn map(&mut self, data: &PixelData, buf: &mut [u8]) -> Result { check_len(&buf, 1)?; if data.has_rgb() { buf[0] = data.luminance() as u8; } else { buf[0] = data.a.unwrap_or(0) as u8; } Ok(1) } fn unmap(&mut self, data: &mut PixelData, buf: &[u8]) -> Result { check_len(&buf, 1)?; data.r = Some(buf[0] as u32); data.g = Some(buf[0] as u32); data.b = Some(buf[0] as u32); data.a = None; Ok(1) } } struct Luminance8Alpha8ub2Descriptor; impl FormatDescriptor for Luminance8Alpha8ub2Descriptor { fn map(&mut self, data: &PixelData, buf: &mut [u8]) -> Result { check_len(&buf, 2)?; buf[0] = data.luminance() as u8; buf[1] = data.a.unwrap_or(255) as u8; Ok(2) } fn unmap(&mut self, data: &mut PixelData, buf: &[u8]) -> Result { check_len(&buf, 2)?; data.r = Some(buf[0] as u32); data.g = Some(buf[0] as u32); data.b = Some(buf[0] as u32); data.a = Some(buf[1] as u32); Ok(2) } } struct Alpha8Luminance8ub2Descriptor; impl FormatDescriptor for Alpha8Luminance8ub2Descriptor { fn map(&mut self, data: &PixelData, buf: &mut [u8]) -> Result { check_len(&buf, 2)?; buf[0] = data.a.unwrap_or(255) as u8; buf[1] = data.luminance() as u8; Ok(2) } fn unmap(&mut self, data: &mut PixelData, buf: &[u8]) -> Result { check_len(&buf, 2)?; data.r = Some(buf[1] as u32); data.g = Some(buf[1] as u32); data.b = Some(buf[1] as u32); data.a = Some(buf[0] as u32); Ok(2) } } struct RGB8ub3Descriptor; impl FormatDescriptor for RGB8ub3Descriptor { fn map(&mut self, data: &PixelData, buf: &mut [u8]) -> Result { check_len(&buf, 3)?; buf[0] = data.r.unwrap_or(0) as u8; buf[1] = data.g.unwrap_or(0) as u8; buf[2] = data.b.unwrap_or(0) as u8; Ok(3) } fn unmap(&mut self, data: &mut PixelData, buf: &[u8]) -> Result { check_len(&buf, 3)?; data.r = Some(buf[0] as u32); data.g = Some(buf[1] as u32); data.b = Some(buf[2] as u32); data.a = None; Ok(3) } } struct RGBA8ub4Descriptor; impl FormatDescriptor for RGBA8ub4Descriptor { fn map(&mut self, data: &PixelData, buf: &mut [u8]) -> Result { check_len(&buf, 4)?; buf[0] = data.r.unwrap_or(0) as u8; buf[1] = data.g.unwrap_or(0) as u8; buf[2] = data.b.unwrap_or(0) as u8; buf[3] = data.a.unwrap_or(0) as u8; Ok(4) } fn unmap(&mut self, data: &mut PixelData, buf: &[u8]) -> Result { check_len(&buf, 4)?; data.r = Some(buf[0] as u32); data.g = Some(buf[1] as u32); data.b = Some(buf[2] as u32); data.a = Some(buf[3] as u32); Ok(4) } } struct ARGB8ub4Descriptor; impl FormatDescriptor for ARGB8ub4Descriptor { fn map(&mut self, data: &PixelData, buf: &mut [u8]) -> Result { check_len(&buf, 4)?; buf[0] = data.a.unwrap_or(0) as u8; buf[1] = data.r.unwrap_or(0) as u8; buf[2] = data.g.unwrap_or(0) as u8; buf[3] = data.b.unwrap_or(0) as u8; Ok(4) } fn unmap(&mut self, data: &mut PixelData, buf: &[u8]) -> Result { check_len(&buf, 4)?; data.a = Some(buf[0] as u32); data.r = Some(buf[1] as u32); data.g = Some(buf[2] as u32); data.b = Some(buf[3] as u32); Ok(4) } } struct BGR8ub3Descriptor; impl FormatDescriptor for BGR8ub3Descriptor { fn map(&mut self, data: &PixelData, buf: &mut [u8]) -> Result { check_len(&buf, 3)?; buf[0] = data.b.unwrap_or(0) as u8; buf[1] = data.g.unwrap_or(0) as u8; buf[2] = data.r.unwrap_or(0) as u8; Ok(3) } fn unmap(&mut self, data: &mut PixelData, buf: &[u8]) -> Result { check_len(&buf, 3)?; data.b = Some(buf[1] as u32); data.g = Some(buf[2] as u32); data.r = Some(buf[3] as u32); data.a = None; Ok(3) } } struct BGRA8ub4Descriptor; impl FormatDescriptor for BGRA8ub4Descriptor { fn map(&mut self, data: &PixelData, buf: &mut [u8]) -> Result { check_len(&buf, 4)?; buf[0] = data.b.unwrap_or(0) as u8; buf[1] = data.g.unwrap_or(0) as u8; buf[2] = data.r.unwrap_or(0) as u8; buf[3] = data.a.unwrap_or(0) as u8; Ok(4) } fn unmap(&mut self, data: &mut PixelData, buf: &[u8]) -> Result { check_len(&buf, 4)?; data.b = Some(buf[0] as u32); data.g = Some(buf[1] as u32); data.r = Some(buf[2] as u32); data.a = Some(buf[3] as u32); Ok(4) } } struct ABGR8ub4Descriptor; impl FormatDescriptor for ABGR8ub4Descriptor { fn map(&mut self, data: &PixelData, buf: &mut [u8]) -> Result { check_len(&buf, 4)?; buf[0] = data.a.unwrap_or(0) as u8; buf[1] = data.b.unwrap_or(0) as u8; buf[2] = data.g.unwrap_or(0) as u8; buf[3] = data.r.unwrap_or(0) as u8; Ok(4) } fn unmap(&mut self, data: &mut PixelData, buf: &[u8]) -> Result { check_len(&buf, 4)?; data.a = Some(buf[0] as u32); data.b = Some(buf[1] as u32); data.g = Some(buf[2] as u32); data.r = Some(buf[3] as u32); Ok(4) } } fn check_len(buf: &[u8], len: usize) -> Result<(), Error> { if buf.len() < len { Err(Error::TextureBufferOverflow) } else { Ok(()) } } /* PixelData */ #[derive(Default)] pub struct PixelData { pub r: Option, pub g: Option, pub b: Option, pub a: Option, } impl PixelData { pub fn has_rgb(&self) -> bool { self.r.is_some() && self.g.is_some() && self.b.is_some() } pub fn luminance(&self) -> u32 { (LUMINANCE_WEIGHT_R * self.r.unwrap_or(0) as f32 + LUMINANCE_WEIGHT_G * self.g.unwrap_or(0) as f32 + LUMINANCE_WEIGHT_B * self.b.unwrap_or(0) as f32) as u32 } } const LUMINANCE_WEIGHT_R: f32 = 0.30; const LUMINANCE_WEIGHT_G: f32 = 0.59; const LUMINANCE_WEIGHT_B: f32 = 0.11; /* FormatInfo */ pub struct FormatInfo { pub gl_format: gl::GLenum, pub gl_format_data: gl::GLenum, pub gl_format_internal: gl::GLenum, pub format_gl_support: Format, pub format_with_alpha: Format, pub format_without_alpha: Format, pub bits_per_pixel: usize, pub r_max: u32, pub g_max: u32, pub b_max: u32, pub a_max: u32, pub r_bits: u32, pub g_bits: u32, pub b_bits: u32, pub a_bits: u32, } impl FormatInfo { pub fn same_size_channels(&self, other: &Self) -> bool { (self.r_bits == other.r_bits || self.r_bits == 0 || other.r_bits == 0) && (self.g_bits == other.g_bits || self.g_bits == 0 || other.g_bits == 0) && (self.b_bits == other.b_bits || self.b_bits == 0 || other.b_bits == 0) && (self.a_bits == other.a_bits || self.a_bits == 0 || other.a_bits == 0) } } static INFO_LUMINANCE8_UB1: FormatInfo = FormatInfo { gl_format: gl::LUMINANCE, gl_format_data: gl::UNSIGNED_BYTE, gl_format_internal: gl::LUMINANCE8, format_gl_support: Format::Luminance8ub1, format_with_alpha: Format::Luminance8Alpha8ub2, format_without_alpha: Format::Luminance8ub1, bits_per_pixel: 8, r_max: 255, g_max: 255, b_max: 255, a_max: 0, r_bits: 8, g_bits: 8, b_bits: 8, a_bits: 0, }; static INFO_LUMINANCE8_ALPHA8_UB2: FormatInfo = FormatInfo { gl_format: gl::LUMINANCE_ALPHA, gl_format_data: gl::UNSIGNED_BYTE, gl_format_internal: gl::LUMINANCE8_ALPHA8, format_gl_support: Format::Luminance8Alpha8ub2, format_with_alpha: Format::Luminance8Alpha8ub2, format_without_alpha: Format::Luminance8ub1, bits_per_pixel: 16, r_max: 255, g_max: 255, b_max: 255, a_max: 255, r_bits: 8, g_bits: 8, b_bits: 8, a_bits: 8, }; static INFO_ALPHA8_LUMINANCE8_UB2: FormatInfo = FormatInfo { gl_format: gl::LUMINANCE_ALPHA, gl_format_data: gl::UNSIGNED_BYTE, gl_format_internal: gl::LUMINANCE8_ALPHA8, format_gl_support: Format::Luminance8Alpha8ub2, format_with_alpha: Format::Alpha8Luminance8ub2, format_without_alpha: Format::Luminance8ub1, bits_per_pixel: 16, r_max: 255, g_max: 255, b_max: 255, a_max: 255, r_bits: 8, g_bits: 8, b_bits: 8, a_bits: 8, }; static INFO_RGB8_UB3: FormatInfo = FormatInfo { gl_format: gl::RGB, gl_format_data: gl::UNSIGNED_BYTE, gl_format_internal: gl::RGB8, format_gl_support: Format::RGB8ub3, format_with_alpha: Format::RGBA8ub4, format_without_alpha: Format::RGB8ub3, bits_per_pixel: 24, r_max: 255, g_max: 255, b_max: 255, a_max: 0, r_bits: 8, g_bits: 8, b_bits: 8, a_bits: 0, }; static INFO_RGBA8_UB4: FormatInfo = FormatInfo { gl_format: gl::RGBA, gl_format_data: gl::UNSIGNED_BYTE, gl_format_internal: gl::RGBA8, format_gl_support: Format::RGBA8ub4, format_with_alpha: Format::RGBA8ub4, format_without_alpha: Format::RGB8ub3, bits_per_pixel: 32, r_max: 255, g_max: 255, b_max: 255, a_max: 255, r_bits: 8, g_bits: 8, b_bits: 8, a_bits: 8, }; static INFO_ARGB8_UB4: FormatInfo = FormatInfo { gl_format: gl::RGBA, gl_format_data: gl::UNSIGNED_INT_8_8_8_8_REV, gl_format_internal: gl::RGBA8, format_gl_support: Format::ARGB8ub4, format_with_alpha: Format::ARGB8ub4, format_without_alpha: Format::RGB8ub3, bits_per_pixel: 32, r_max: 255, g_max: 255, b_max: 255, a_max: 255, r_bits: 8, g_bits: 8, b_bits: 8, a_bits: 8, }; static INFO_BGR8_UB3: FormatInfo = FormatInfo { gl_format: gl::BGR, gl_format_data: gl::UNSIGNED_BYTE, gl_format_internal: gl::RGB8, format_gl_support: Format::BGR8ub3, format_with_alpha: Format::BGRA8ub4, format_without_alpha: Format::BGR8ub3, bits_per_pixel: 24, r_max: 255, g_max: 255, b_max: 255, a_max: 0, r_bits: 8, g_bits: 8, b_bits: 8, a_bits: 0, }; static INFO_BGRA8_UB4: FormatInfo = FormatInfo { gl_format: gl::BGR, gl_format_data: gl::UNSIGNED_BYTE, gl_format_internal: gl::RGBA8, format_gl_support: Format::BGRA8ub4, format_with_alpha: Format::BGRA8ub4, format_without_alpha: Format::BGR8ub3, bits_per_pixel: 32, r_max: 255, g_max: 255, b_max: 255, a_max: 255, r_bits: 8, g_bits: 8, b_bits: 8, a_bits: 8, }; static INFO_ABGR8_UB4: FormatInfo = FormatInfo { gl_format: gl::BGR, gl_format_data: gl::UNSIGNED_INT_8_8_8_8_REV, gl_format_internal: gl::RGBA8, format_gl_support: Format::ABGR8ub4, format_with_alpha: Format::ABGR8ub4, format_without_alpha: Format::BGR8ub3, bits_per_pixel: 32, r_max: 255, g_max: 255, b_max: 255, a_max: 255, r_bits: 8, g_bits: 8, b_bits: 8, a_bits: 8, }; /* Format */ #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Format { /// [LLLL_LLLL] Luminance8ub1, /// [LLLL_LLLL][AAAA_AAAA] Luminance8Alpha8ub2, /// [AAAA_AAAA][LLLL_LLLL] Alpha8Luminance8ub2, /// [RRRR_RRRR][GGGG_GGGG][BBBB_BBBB] RGB8ub3, /// [RRRR_RRRR][GGGG_GGGG][BBBB_BBBB][AAAA_AAAA] RGBA8ub4, /// [AAAA_AAAA][RRRR_RRRR][GGGG_GGGG][BBBB_BBBB] ARGB8ub4, /// [BBBB_BBBB][GGGG_GGGG][RRRR_RRRR] BGR8ub3, /// [BBBB_BBBB][GGGG_GGGG][RRRR_RRRR][AAAA_AAAA] BGRA8ub4, /// [AAAA_AAAA][BBBB_BBBB][GGGG_GGGG][RRRR_RRRR] ABGR8ub4, } impl Format { pub fn info(&self) -> &'static FormatInfo { match self { Format::Luminance8ub1 => &INFO_LUMINANCE8_UB1, Format::Luminance8Alpha8ub2 => &INFO_LUMINANCE8_ALPHA8_UB2, Format::Alpha8Luminance8ub2 => &INFO_ALPHA8_LUMINANCE8_UB2, Format::RGB8ub3 => &INFO_RGB8_UB3, Format::RGBA8ub4 => &INFO_RGBA8_UB4, Format::ARGB8ub4 => &INFO_ARGB8_UB4, Format::BGR8ub3 => &INFO_BGR8_UB3, Format::BGRA8ub4 => &INFO_BGRA8_UB4, Format::ABGR8ub4 => &INFO_ABGR8_UB4, } } pub fn descriptor(&self) -> Box { match self { Format::Luminance8ub1 => Box::new(Luminance8ub1Descriptor), Format::Luminance8Alpha8ub2 => Box::new(Luminance8Alpha8ub2Descriptor), Format::Alpha8Luminance8ub2 => Box::new(Alpha8Luminance8ub2Descriptor), Format::RGB8ub3 => Box::new(RGB8ub3Descriptor), Format::RGBA8ub4 => Box::new(RGBA8ub4Descriptor), Format::ARGB8ub4 => Box::new(ARGB8ub4Descriptor), Format::BGR8ub3 => Box::new(BGR8ub3Descriptor), Format::BGRA8ub4 => Box::new(BGRA8ub4Descriptor), Format::ABGR8ub4 => Box::new(ABGR8ub4Descriptor), } } pub fn is_bit_equal(&self, _other: &Self) -> bool { false } } /* Target */ pub enum Target { Texture1D, Texture2D, Texture3D, Texture1DArray, Texture2DArray, TextureRectangle, TextureCubeMap, TextureCubeMapArray, TextureBuffer, Texture2DMultisample, Texture2DMultisampleArray, } impl AsEnum for Target { fn as_enum(&self) -> gl::GLenum { match self { Self::Texture1D => gl::TEXTURE_1D, Self::Texture2D => gl::TEXTURE_2D, Self::Texture3D => gl::TEXTURE_3D, Self::Texture1DArray => gl::TEXTURE_1D_ARRAY, Self::Texture2DArray => gl::TEXTURE_2D_ARRAY, Self::TextureRectangle => gl::TEXTURE_RECTANGLE, Self::TextureCubeMap => gl::TEXTURE_CUBE_MAP, Self::TextureCubeMapArray => gl::TEXTURE_CUBE_MAP_ARRAY, Self::TextureBuffer => gl::TEXTURE_BUFFER, Self::Texture2DMultisample => gl::TEXTURE_2D_MULTISAMPLE, Self::Texture2DMultisampleArray => gl::TEXTURE_2D_MULTISAMPLE_ARRAY, } } } /* FilterMin */ pub enum FilterMin { /// Returns the value of the texture element that is nearest /// (in Manhattan distance) to the specified texture coordinates. Nearest, /// Returns the weighted average of the four texture elements /// that are closest to the specified texture coordinates. /// These can include items wrapped or repeated from other parts /// of a texture, depending on the values of GL_TEXTURE_WRAP_S /// and GL_TEXTURE_WRAP_T, and on the exact mapping. Linear, /// Chooses the mipmap that most closely matches the size of the /// pixel being textured and uses the GL_NEAREST criterion (the /// texture element closest to the specified texture coordinates) /// to produce a texture value. NearestMipmapNearest, /// Chooses the mipmap that most closely matches the size of the pixel /// being textured and uses the GL_LINEAR criterion (a weighted average /// of the four texture elements that are closest to the specified /// texture coordinates) to produce a texture value. LinearMipmapNearest, /// Chooses the two mipmaps that most closely match the size of the pixel /// being textured and uses the GL_NEAREST criterion (the texture element /// closest to the specified texture coordinates ) to produce a texture /// value from each mipmap. The final texture value is a weighted average /// of those two values. NearestMipmapLinear, /// Chooses the two mipmaps that most closely match the size of the pixel /// being textured and uses the GL_LINEAR criterion (a weighted average of /// the texture elements that are closest to the specified texture coordinates) /// to produce a texture value from each mipmap. The final texture value /// is a weighted average of those two values. LinearMipmapLinear, } impl AsEnum for FilterMin { fn as_enum(&self) -> gl::GLenum { match self { Self::Nearest => gl::NEAREST, Self::Linear => gl::LINEAR, Self::NearestMipmapNearest => gl::NEAREST_MIPMAP_NEAREST, Self::LinearMipmapNearest => gl::LINEAR_MIPMAP_NEAREST, Self::NearestMipmapLinear => gl::NEAREST_MIPMAP_LINEAR, Self::LinearMipmapLinear => gl::LINEAR_MIPMAP_LINEAR, } } } /* FilterMag */ pub enum FilterMag { /// Returns the value of the texture element that is nearest /// (in Manhattan distance) to the specified texture coordinates. Nearest, /// Returns the weighted average of the texture elements that are /// closest to the specified texture coordinates. These can include /// items wrapped or repeated from other parts of a texture, depending /// on the values of GL_TEXTURE_WRAP_S and GL_TEXTURE_WRAP_T, and on /// the exact mapping. Linear, } impl AsEnum for FilterMag { fn as_enum(&self) -> gl::GLenum { match self { Self::Nearest => gl::NEAREST, Self::Linear => gl::LINEAR, } } } /* Wrap */ pub enum Wrap { ClampToEdge, ClampToBorder, MirrorRepeat, Repeat, MirrorClampToEdge, } impl AsEnum for Wrap { fn as_enum(&self) -> gl::GLenum { match self { Self::ClampToEdge => gl::CLAMP_TO_EDGE, Self::ClampToBorder => gl::CLAMP_TO_BORDER, Self::MirrorRepeat => gl::MIRRORED_REPEAT, Self::Repeat => gl::REPEAT, Self::MirrorClampToEdge => gl::MIRROR_CLAMP_TO_EDGE, } } }