|
|
@@ -0,0 +1,914 @@ |
|
|
|
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<Self, Error> { |
|
|
|
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 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 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<u8>, |
|
|
|
} |
|
|
|
|
|
|
|
impl Data { |
|
|
|
pub fn from_parts(width: usize, height: usize, format: Format, buffer: Vec<u8>) -> Self { |
|
|
|
Self { |
|
|
|
width, |
|
|
|
height, |
|
|
|
format, |
|
|
|
buffer, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
pub fn from_reader<R>(reader: &mut R) -> Result<Self, Error> |
|
|
|
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<P>(path: P) -> Result<Self, Error> |
|
|
|
where |
|
|
|
P: AsRef<Path>, |
|
|
|
{ |
|
|
|
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<F>(&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<usize, Error>; |
|
|
|
fn unmap(&mut self, data: &mut PixelData, buf: &[u8]) -> Result<usize, Error>; |
|
|
|
} |
|
|
|
|
|
|
|
struct Luminance8ub1Descriptor; |
|
|
|
|
|
|
|
impl FormatDescriptor for Luminance8ub1Descriptor { |
|
|
|
fn map(&mut self, data: &PixelData, buf: &mut [u8]) -> Result<usize, Error> { |
|
|
|
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<usize, Error> { |
|
|
|
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<usize, Error> { |
|
|
|
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<usize, Error> { |
|
|
|
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<usize, Error> { |
|
|
|
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<usize, Error> { |
|
|
|
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<usize, Error> { |
|
|
|
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<usize, Error> { |
|
|
|
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<usize, Error> { |
|
|
|
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<usize, Error> { |
|
|
|
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<usize, Error> { |
|
|
|
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<usize, Error> { |
|
|
|
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<usize, Error> { |
|
|
|
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<usize, Error> { |
|
|
|
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<usize, Error> { |
|
|
|
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<usize, Error> { |
|
|
|
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<usize, Error> { |
|
|
|
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<usize, Error> { |
|
|
|
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<u32>, |
|
|
|
pub g: Option<u32>, |
|
|
|
pub b: Option<u32>, |
|
|
|
pub a: Option<u32>, |
|
|
|
} |
|
|
|
|
|
|
|
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<dyn FormatDescriptor> { |
|
|
|
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, |
|
|
|
} |
|
|
|
} |
|
|
|
} |