use crate::core::*;
pub struct Screen {}
impl Screen {
pub fn write<F: FnOnce() -> Result<(), Error>>(gl: &Gl, x: i32, y: i32, width: usize, height: usize,
clear_color: Option<&Vec4>, clear_depth: Option<f32>, render: F) -> Result<(), Error>
{
gl.viewport(x, y, width, height);
gl.bind_framebuffer(consts::DRAW_FRAMEBUFFER, None);
RenderTarget::clear(gl, clear_color, clear_depth);
render()?;
Ok(())
}
#[cfg(not(target_arch = "wasm32"))]
pub fn read_color(gl: &Gl, x: i32, y: i32, width: usize, height: usize) -> Result<Vec<u8>, Error>
{
gl.viewport(x, y, width, height);
let mut pixels = vec![0u8; width * height * 3];
gl.bind_framebuffer(consts::READ_FRAMEBUFFER, None);
gl.read_pixels_with_u8_data(x as u32, y as u32, width as u32, height as u32, consts::RGB,
consts::UNSIGNED_BYTE, &mut pixels);
Ok(pixels)
}
#[cfg(not(target_arch = "wasm32"))]
pub fn read_depth(gl: &Gl, x: i32, y: i32, width: usize, height: usize) -> Result<Vec<f32>, Error>
{
gl.viewport(x, y, width, height);
let mut pixels = vec![0f32; width * height];
gl.bind_framebuffer(consts::READ_FRAMEBUFFER, None);
gl.read_pixels_with_f32_data(x as u32, y as u32, width as u32, height as u32,
consts::DEPTH_COMPONENT, consts::FLOAT, &mut pixels);
Ok(pixels)
}
}
pub struct RenderTarget {}
impl RenderTarget
{
pub fn write_to_color<F: FnOnce() -> Result<(), Error>>(gl: &Gl, x: i32, y: i32, width: usize, height: usize,
clear_color: Option<&Vec4>, color_texture: Option<&Texture2D>, render: F) -> Result<(), Error>
{
Self::write(gl, x, y, width, height, clear_color, None, color_texture, None, render)
}
pub fn write_to_depth<F: FnOnce() -> Result<(), Error>>(gl: &Gl, x: i32, y: i32, width: usize, height: usize,
clear_depth: Option<f32>, depth_texture: Option<&Texture2D>, render: F) -> Result<(), Error>
{
Self::write(gl, x, y, width, height, None, clear_depth, None, depth_texture, render)
}
pub fn write<F: FnOnce() -> Result<(), Error>>(gl: &Gl, x: i32, y: i32, width: usize, height: usize,
clear_color: Option<&Vec4>, clear_depth: Option<f32>,
color_texture: Option<&Texture2D>, depth_texture: Option<&Texture2D>,
render: F) -> Result<(), Error>
{
gl.viewport(x, y, width, height);
let id = RenderTarget::new_framebuffer(gl, if color_texture.is_some() {1} else {0})?;
if let Some(color_texture) = color_texture {
color_texture.bind_as_color_target(0);
}
if let Some(depth_texture) = depth_texture {
depth_texture.bind_as_depth_target();
}
#[cfg(feature = "debug")]
{
gl.check_framebuffer_status().or_else(|message| Err(Error::FailedToCreateFramebuffer {message}))?;
}
RenderTarget::clear(gl, clear_color, clear_depth);
render()?;
gl.delete_framebuffer(Some(&id));
if let Some(color_texture) = color_texture {
color_texture.generate_mip_maps();
}
if let Some(depth_texture) = depth_texture {
depth_texture.generate_mip_maps();
}
Ok(())
}
pub fn write_to_color_array<F: FnOnce() -> Result<(), Error>>(gl: &Gl, x: i32, y: i32, width: usize, height: usize,
clear_color: Option<&Vec4>,
color_texture_array: Option<&Texture2DArray>,
color_channel_count: usize, color_channel_to_texture_layer: &dyn Fn(usize) -> usize,
render: F) -> Result<(), Error>
{
Self::write_array(gl, x, y, width, height, clear_color, None, color_texture_array, None, color_channel_count, color_channel_to_texture_layer, 0, render)
}
pub fn write_to_depth_array<F: FnOnce() -> Result<(), Error>>(gl: &Gl, x: i32, y: i32, width: usize, height: usize, clear_depth: Option<f32>,
depth_texture_array: Option<&Texture2DArray>, depth_layer: usize,
render: F) -> Result<(), Error>
{
Self::write_array(gl, x, y, width, height,None, clear_depth, None, depth_texture_array, 0, &|i| {i}, depth_layer, render)
}
pub fn write_array<F: FnOnce() -> Result<(), Error>>(gl: &Gl, x: i32, y: i32, width: usize, height: usize,
clear_color: Option<&Vec4>, clear_depth: Option<f32>,
color_texture_array: Option<&Texture2DArray>,
depth_texture_array: Option<&Texture2DArray>,
color_channel_count: usize, color_channel_to_texture_layer: &dyn Fn(usize) -> usize,
depth_layer: usize, render: F) -> Result<(), Error>
{
gl.viewport(x, y, width, height);
let id = RenderTarget::new_framebuffer(gl, color_channel_count)?;
if let Some(color_texture) = color_texture_array {
for channel in 0..color_channel_count {
color_texture.bind_as_color_target(color_channel_to_texture_layer(channel), channel);
}
}
if let Some(depth_texture) = depth_texture_array {
depth_texture.bind_as_depth_target(depth_layer);
}
#[cfg(feature = "debug")]
{
gl.check_framebuffer_status().or_else(|message| Err(Error::FailedToCreateFramebuffer {message}))?;
}
RenderTarget::clear(gl, clear_color, clear_depth);
render()?;
gl.delete_framebuffer(Some(&id));
if let Some(color_texture) = color_texture_array {
color_texture.generate_mip_maps();
}
if let Some(depth_texture) = depth_texture_array {
depth_texture.generate_mip_maps();
}
Ok(())
}
fn new_framebuffer(gl: &Gl, no_color_channels: usize) -> Result<crate::gl::Framebuffer, Error>
{
let id = gl.create_framebuffer()
.ok_or_else(|| Error::FailedToCreateFramebuffer {message: "Failed to create framebuffer".to_string()} )?;
gl.bind_framebuffer(consts::DRAW_FRAMEBUFFER, Some(&id));
if no_color_channels > 0 {
let mut draw_buffers = Vec::new();
for i in 0..no_color_channels {
draw_buffers.push(consts::COLOR_ATTACHMENT0 + i as u32);
}
gl.draw_buffers(&draw_buffers);
}
Ok(id)
}
fn clear(gl: &Gl, clear_color: Option<&Vec4>, clear_depth: Option<f32>) {
if let Some(color) = clear_color {
if let Some(depth) = clear_depth {
gl.clear_color(color.x, color.y, color.z, color.w);
depth_write(gl,true);
gl.clear_depth(depth);
gl.clear(consts::COLOR_BUFFER_BIT | consts::DEPTH_BUFFER_BIT);
}
else {
gl.clear_color(color.x, color.y, color.z, color.w);
gl.clear(consts::COLOR_BUFFER_BIT);
}
} else if let Some(depth) = clear_depth {
gl.clear_depth(depth);
depth_write(gl, true);
gl.clear(consts::DEPTH_BUFFER_BIT);
}
}
}