use crate::*;
pub use glow;
use glow::*;
pub struct ImageTexture<T: Type, C: Color> {
pub framebuffer: Framebuffer,
pub texture: Texture,
_t: std::marker::PhantomData<(T, C)>,
}
impl<T: Type, C: Color> ImageTexture<T, C> {
pub fn new(framebuffer: Framebuffer, texture: Texture) -> Self {
ImageTexture {
framebuffer,
texture,
_t: std::marker::PhantomData,
}
}
}
pub trait ToTexture<T: Type, C: Color> {
const COLOR: u32;
const KIND: u32;
fn get_meta(&self) -> &Meta<T, C>;
fn get_data(&self) -> &[u8];
fn internal(&self) -> Result<u32, Error> {
let internal = match (Self::COLOR, Self::KIND) {
(glow::RED, glow::BYTE) => glow::R8,
(glow::RED, glow::SHORT) => glow::R16,
(glow::RED, glow::UNSIGNED_BYTE) => glow::R8,
(glow::RED, glow::UNSIGNED_SHORT) => glow::R16,
(glow::RED, glow::INT) => glow::R32I,
(glow::RED, glow::UNSIGNED_INT) => glow::R32UI,
(glow::RED, glow::FLOAT) => glow::R32F,
(glow::RGB, glow::BYTE) => glow::RGB8,
(glow::RGB, glow::SHORT) => glow::RGB16,
(glow::RGB, glow::UNSIGNED_BYTE) => glow::RGB,
(glow::RGB, glow::UNSIGNED_SHORT) => glow::RGB16,
(glow::RGB, glow::INT) => glow::RGB32I,
(glow::RGB, glow::UNSIGNED_INT) => glow::RGB32UI,
(glow::RGB, glow::FLOAT) => glow::RGB32F,
(glow::RGBA, glow::BYTE) => glow::RGBA,
(glow::RGBA, glow::SHORT) => glow::RGBA16,
(glow::RGBA, glow::UNSIGNED_BYTE) => glow::RGBA,
(glow::RGBA, glow::UNSIGNED_SHORT) => glow::RGBA16,
(glow::RGBA, glow::INT) => glow::RGBA32I,
(glow::RGBA, glow::UNSIGNED_INT) => glow::RGBA32UI,
(glow::RGBA, glow::FLOAT) => glow::RGBA32F,
_ => return Err(Error::InvalidType),
};
Ok(internal)
}
fn create_image_texture(&self, gl: &glow::Context) -> Result<ImageTexture<T, C>, Error> {
unsafe {
let framebuffer = gl
.create_framebuffer()
.expect("Unable to create framebuffer");
let texture = gl.create_texture().expect("Unable to create texture");
let image_texture = ImageTexture::<T, C>::new(framebuffer, texture);
gl.bind_texture(glow::TEXTURE_2D, Some(texture));
gl.tex_parameter_i32(
glow::TEXTURE_2D,
glow::TEXTURE_MAG_FILTER,
glow::NEAREST as i32,
);
gl.tex_parameter_i32(
glow::TEXTURE_2D,
glow::TEXTURE_MIN_FILTER,
glow::NEAREST as i32,
);
let meta = self.get_meta();
gl.tex_image_2d(
glow::TEXTURE_2D,
0,
self.internal()? as i32,
meta.width() as i32,
meta.height() as i32,
0,
Self::COLOR,
Self::KIND,
Some(self.get_data()),
);
gl.bind_texture(glow::TEXTURE_2D, None);
gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(image_texture.framebuffer));
gl.framebuffer_texture_2d(
glow::READ_FRAMEBUFFER,
glow::COLOR_ATTACHMENT0,
glow::TEXTURE_2D,
Some(texture),
0,
);
gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None);
Ok(image_texture)
}
}
fn draw_image_texture(
&self,
gl: &glow::Context,
image_texture: &ImageTexture<T, C>,
display_size: Size,
offset: Point,
) -> Result<(), Error> {
let x = offset.x;
let y = offset.y;
let display_width = display_size.width;
let display_height = display_size.height;
unsafe {
gl.bind_texture(glow::TEXTURE_2D, Some(image_texture.texture));
let meta = self.get_meta();
gl.tex_image_2d(
glow::TEXTURE_2D,
0,
self.internal()? as i32,
meta.width() as i32,
meta.height() as i32,
0,
Self::COLOR,
Self::KIND,
Some(self.get_data()),
);
gl.bind_texture(glow::TEXTURE_2D, None);
gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(image_texture.framebuffer));
gl.framebuffer_texture_2d(
glow::READ_FRAMEBUFFER,
glow::COLOR_ATTACHMENT0,
glow::TEXTURE_2D,
Some(image_texture.texture),
0,
);
gl.blit_framebuffer(
0,
meta.height() as i32,
meta.width() as i32,
0,
x as i32,
y as i32,
x as i32 + display_width as i32,
y as i32 + display_height as i32,
glow::COLOR_BUFFER_BIT,
glow::NEAREST,
);
gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None);
}
Ok(())
}
}
macro_rules! to_texture {
($t:ty, $c:ty, $kind:expr, $color:expr) => {
impl ToTexture<$t, $c> for Image<$t, $c> {
const COLOR: u32 = $color;
const KIND: u32 = $kind;
fn get_meta(&self) -> &Meta<$t, $c> {
&self.meta
}
fn get_data(&self) -> &[u8] {
self.buffer()
}
}
};
}
to_texture!(f32, Rgb, glow::FLOAT, glow::RGB);
to_texture!(f32, Srgb, glow::FLOAT, glow::RGB);
to_texture!(f32, Rgba, glow::FLOAT, glow::RGBA);
to_texture!(f32, Srgba, glow::FLOAT, glow::RGBA);
to_texture!(u16, Rgb, glow::UNSIGNED_SHORT, glow::RGB);
to_texture!(u16, Srgb, glow::UNSIGNED_SHORT, glow::RGB);
to_texture!(u16, Rgba, glow::UNSIGNED_SHORT, glow::RGBA);
to_texture!(u16, Srgba, glow::UNSIGNED_SHORT, glow::RGBA);
to_texture!(i16, Rgb, glow::SHORT, glow::RGB);
to_texture!(i16, Srgb, glow::SHORT, glow::RGB);
to_texture!(i16, Rgba, glow::SHORT, glow::RGBA);
to_texture!(i16, Srgba, glow::SHORT, glow::RGBA);
to_texture!(u8, Rgb, glow::UNSIGNED_BYTE, glow::RGB);
to_texture!(u8, Srgb, glow::UNSIGNED_BYTE, glow::RGB);
to_texture!(u8, Rgba, glow::UNSIGNED_BYTE, glow::RGBA);
to_texture!(u8, Srgba, glow::UNSIGNED_BYTE, glow::RGBA);