use super::*;
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum RenderTextureResizing {
Resizable,
ResizableScaled(f32),
NonResizable
}
pub struct RenderTexture<T: RenderTextureType> {
texture: GLTexture,
pbo: GLPBO,
src_width: u32,
src_height: u32,
width: u32,
height: u32,
ty: u32,
pixels: Vec<T>,
use_pbo: bool,
resizing: RenderTextureResizing
}
impl<T: RenderTextureType> RenderTexture<T> {
pub(crate) fn new(width: u32, height: u32, use_pbo: bool, resizing: RenderTextureResizing) -> RenderTexture<T> {
let src_width = width;
let src_height = height;
let (width, height) = Self::get_sized_dims(width, height, resizing);
gl_pixel_store_i(gl::UNPACK_ALIGNMENT, 1);
let size = (width * height * std::mem::size_of::<T>() as u32 * 3) as usize;
let texture = GLTexture::new(gl::TEXTURE_2D);
let mut pbo = GLPBO::new();
let pixels = vec![T::default(); size / std::mem::size_of::<T>()];
let ty = T::get_type();
texture.bind(); {
gl_tex_parami(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE);
gl_tex_parami(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE);
gl_tex_parami(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST);
gl_tex_parami(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST);
gl_tex_image_2d(gl::RGB, width as i32, height as i32, gl::RGB, ty, std::ptr::null());
pbo.bind();
pbo.allocate(size);
pbo.unbind();
} texture.unbind();
gl_pixel_store_i(gl::UNPACK_ALIGNMENT, 4);
RenderTexture {
texture,
pbo,
src_width,
src_height,
width,
height,
ty,
pixels,
use_pbo,
resizing
}
}
pub(crate) fn bind(&self, slot: u32) {
gl_active_texture(slot);
self.texture.bind();
}
pub(crate) fn async_write(&mut self) {
if self.use_pbo {
self.pbo.bind();
let pixels = self.pbo.map() as *mut T;
unsafe {
pixels.copy_from_nonoverlapping(self.pixels.as_ptr(), self.pixels.len());
}
self.pbo.unmap();
self.pbo.unbind();
}
}
pub(crate) fn flush_write(&mut self) {
if self.use_pbo {
self.pbo.bind();
gl_pixel_store_i(gl::UNPACK_ALIGNMENT, 1);
self.texture.bind();
gl_tex_sub_image_2d(self.width as i32, self.height as i32, gl::RGB, self.ty, std::ptr::null());
self.texture.unbind();
gl_pixel_store_i(gl::UNPACK_ALIGNMENT, 4);
self.pbo.unbind();
} else {
self.texture.bind();
gl_tex_sub_image_2d(self.width as i32, self.height as i32, gl::RGB, self.ty, self.pixels.as_ptr() as *const std::ffi::c_void);
self.texture.unbind();
}
}
pub fn resize(&mut self, width: u32, height: u32) {
self.src_width = width;
self.src_height = height;
if let RenderTextureResizing::NonResizable = self.resizing {
return;
}
self.internal_resize(width, height);
}
fn internal_resize(&mut self, width: u32, height: u32) {
self.src_width = width;
self.src_height = height;
let (width, height) = Self::get_sized_dims(width, height, self.resizing);
self.width = width;
self.height = height;
gl_finish();
gl_pixel_store_i(gl::UNPACK_ALIGNMENT, 1);
let size = (width * height * std::mem::size_of::<T>() as u32 * 3) as usize;
self.texture = GLTexture::new(gl::TEXTURE_2D);
self.pbo = GLPBO::new();
self.pixels = vec![T::default(); size / std::mem::size_of::<T>()];
self.texture.bind(); {
gl_tex_parami(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE);
gl_tex_parami(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE);
gl_tex_parami(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST);
gl_tex_parami(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST);
gl_tex_image_2d(gl::RGB, width as i32, height as i32, gl::RGB, self.ty, std::ptr::null());
self.pbo.bind();
self.pbo.allocate(size);
self.pbo.unbind();
} self.texture.unbind();
gl_pixel_store_i(gl::UNPACK_ALIGNMENT, 4);
}
fn get_sized_dims(width: u32, height: u32, resizing: RenderTextureResizing) -> (u32, u32) {
match resizing {
RenderTextureResizing::ResizableScaled(scale) => {
((width as f32 * scale) as u32, (height as f32 * scale) as u32)
},
_ => (width, height)
}
}
#[inline(always)]
pub fn get_pixel(&self, x: u32, y: u32) -> (T, T, T) {
let i = ((y * self.width + x) * 3) as usize;
(self.pixels[i], self.pixels[i + 1], self.pixels[i + 2])
}
#[inline(always)]
pub fn set_pixel(&mut self, x: u32, y: u32, r: T, g: T, b: T) {
let i = ((y * self.width + x) * 3) as usize;
self.pixels[i] = r;
self.pixels[i + 1] = g;
self.pixels[i + 2] = b;
}
#[inline(always)]
pub fn get_width(&self) -> u32 {
self.width
}
#[inline(always)]
pub fn get_height(&self) -> u32 {
self.height
}
#[inline(always)]
pub fn get_resizing_mode(&self) -> RenderTextureResizing {
self.resizing
}
pub fn set_resizing_mode(&mut self, resizing: RenderTextureResizing) {
self.resizing = resizing;
self.internal_resize(self.src_width, self.src_height);
}
}