2021-11-03 18:17:07 +00:00
|
|
|
#![allow(unsafe_code)]
|
2022-03-22 15:04:06 +00:00
|
|
|
use crate::check_for_gl_error;
|
|
|
|
use crate::misc_util::{compile_shader, link_program};
|
|
|
|
use crate::vao::BufferInfo;
|
|
|
|
use glow::HasContext as _;
|
2021-11-03 18:17:07 +00:00
|
|
|
|
|
|
|
/// Uses a framebuffer to render everything in linear color space and convert it back to `sRGB`
|
|
|
|
/// in a separate "post processing" step
|
|
|
|
pub(crate) struct PostProcess {
|
2022-03-14 12:25:11 +00:00
|
|
|
gl: std::rc::Rc<glow::Context>,
|
2021-11-03 18:17:07 +00:00
|
|
|
pos_buffer: glow::Buffer,
|
|
|
|
index_buffer: glow::Buffer,
|
2022-03-22 22:11:27 +00:00
|
|
|
vao: crate::vao::VertexArrayObject,
|
2021-11-03 18:17:07 +00:00
|
|
|
is_webgl_1: bool,
|
2022-04-15 10:41:42 +00:00
|
|
|
color_texture: glow::Texture,
|
|
|
|
depth_renderbuffer: Option<glow::Renderbuffer>,
|
2021-11-03 18:17:07 +00:00
|
|
|
texture_size: (i32, i32),
|
|
|
|
fbo: glow::Framebuffer,
|
|
|
|
program: glow::Program,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PostProcess {
|
|
|
|
pub(crate) unsafe fn new(
|
2022-03-14 12:25:11 +00:00
|
|
|
gl: std::rc::Rc<glow::Context>,
|
2021-11-13 11:32:01 +00:00
|
|
|
shader_prefix: &str,
|
2021-11-03 18:17:07 +00:00
|
|
|
is_webgl_1: bool,
|
2022-04-15 10:41:42 +00:00
|
|
|
[width, height]: [i32; 2],
|
2021-11-03 18:17:07 +00:00
|
|
|
) -> Result<PostProcess, String> {
|
2022-04-15 10:41:42 +00:00
|
|
|
gl.pixel_store_i32(glow::UNPACK_ALIGNMENT, 1);
|
|
|
|
|
2021-11-03 18:17:07 +00:00
|
|
|
let fbo = gl.create_framebuffer()?;
|
|
|
|
|
|
|
|
gl.bind_framebuffer(glow::FRAMEBUFFER, Some(fbo));
|
|
|
|
|
2022-04-15 10:41:42 +00:00
|
|
|
// ----------------------------------------------
|
|
|
|
// Set up color tesxture:
|
2021-11-03 18:17:07 +00:00
|
|
|
|
2022-04-15 10:41:42 +00:00
|
|
|
let color_texture = gl.create_texture()?;
|
|
|
|
gl.bind_texture(glow::TEXTURE_2D, Some(color_texture));
|
2021-11-03 18:17:07 +00:00
|
|
|
gl.tex_parameter_i32(
|
|
|
|
glow::TEXTURE_2D,
|
|
|
|
glow::TEXTURE_WRAP_S,
|
|
|
|
glow::CLAMP_TO_EDGE as i32,
|
|
|
|
);
|
|
|
|
gl.tex_parameter_i32(
|
|
|
|
glow::TEXTURE_2D,
|
|
|
|
glow::TEXTURE_WRAP_T,
|
|
|
|
glow::CLAMP_TO_EDGE as i32,
|
|
|
|
);
|
|
|
|
gl.tex_parameter_i32(
|
|
|
|
glow::TEXTURE_2D,
|
|
|
|
glow::TEXTURE_MIN_FILTER,
|
|
|
|
glow::NEAREST as i32,
|
|
|
|
);
|
|
|
|
gl.tex_parameter_i32(
|
|
|
|
glow::TEXTURE_2D,
|
|
|
|
glow::TEXTURE_MAG_FILTER,
|
|
|
|
glow::NEAREST as i32,
|
|
|
|
);
|
|
|
|
|
|
|
|
let (internal_format, format) = if is_webgl_1 {
|
|
|
|
(glow::SRGB_ALPHA, glow::SRGB_ALPHA)
|
|
|
|
} else {
|
|
|
|
(glow::SRGB8_ALPHA8, glow::RGBA)
|
|
|
|
};
|
|
|
|
|
|
|
|
gl.tex_image_2d(
|
|
|
|
glow::TEXTURE_2D,
|
|
|
|
0,
|
|
|
|
internal_format as i32,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
0,
|
|
|
|
format,
|
|
|
|
glow::UNSIGNED_BYTE,
|
|
|
|
None,
|
|
|
|
);
|
2022-03-22 15:04:06 +00:00
|
|
|
check_for_gl_error!(&gl, "post process texture initialization");
|
2021-11-03 18:17:07 +00:00
|
|
|
|
|
|
|
gl.framebuffer_texture_2d(
|
|
|
|
glow::FRAMEBUFFER,
|
|
|
|
glow::COLOR_ATTACHMENT0,
|
|
|
|
glow::TEXTURE_2D,
|
2022-04-15 10:41:42 +00:00
|
|
|
Some(color_texture),
|
2021-11-03 18:17:07 +00:00
|
|
|
0,
|
|
|
|
);
|
|
|
|
gl.bind_texture(glow::TEXTURE_2D, None);
|
2022-04-15 10:41:42 +00:00
|
|
|
|
|
|
|
// ---------------------------------------------------------
|
|
|
|
// Depth buffer - we only need this when embedding 3D within egui using `egui::PaintCallback`.
|
|
|
|
// TODO: add a setting to enable/disable the depth buffer.
|
|
|
|
|
|
|
|
let with_depth_buffer = true;
|
|
|
|
let depth_renderbuffer = if with_depth_buffer {
|
|
|
|
let depth_renderbuffer = gl.create_renderbuffer()?;
|
|
|
|
gl.bind_renderbuffer(glow::RENDERBUFFER, Some(depth_renderbuffer));
|
|
|
|
gl.renderbuffer_storage(glow::RENDERBUFFER, glow::DEPTH_COMPONENT16, width, height);
|
|
|
|
gl.bind_renderbuffer(glow::RENDERBUFFER, None);
|
|
|
|
Some(depth_renderbuffer)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
|
|
|
// ---------------------------------------------------------
|
|
|
|
|
2021-11-03 18:17:07 +00:00
|
|
|
gl.bind_framebuffer(glow::FRAMEBUFFER, None);
|
|
|
|
|
2022-04-15 10:41:42 +00:00
|
|
|
// ---------------------------------------------------------
|
|
|
|
|
2021-11-03 18:17:07 +00:00
|
|
|
let vert_shader = compile_shader(
|
2022-03-14 12:25:11 +00:00
|
|
|
&gl,
|
2021-11-03 18:17:07 +00:00
|
|
|
glow::VERTEX_SHADER,
|
2021-11-13 11:32:01 +00:00
|
|
|
&format!(
|
|
|
|
"{}\n{}",
|
|
|
|
shader_prefix,
|
|
|
|
include_str!("shader/post_vertex_100es.glsl")
|
|
|
|
),
|
2021-11-03 18:17:07 +00:00
|
|
|
)?;
|
|
|
|
let frag_shader = compile_shader(
|
2022-03-14 12:25:11 +00:00
|
|
|
&gl,
|
2021-11-03 18:17:07 +00:00
|
|
|
glow::FRAGMENT_SHADER,
|
2021-11-13 11:32:01 +00:00
|
|
|
&format!(
|
|
|
|
"{}\n{}",
|
|
|
|
shader_prefix,
|
|
|
|
include_str!("shader/post_fragment_100es.glsl")
|
|
|
|
),
|
2021-11-03 18:17:07 +00:00
|
|
|
)?;
|
2022-03-14 12:25:11 +00:00
|
|
|
let program = link_program(&gl, [vert_shader, frag_shader].iter())?;
|
2021-11-03 18:17:07 +00:00
|
|
|
|
2022-04-15 10:41:42 +00:00
|
|
|
let positions: Vec<f32> = vec![0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0];
|
2021-11-03 18:17:07 +00:00
|
|
|
|
2022-04-15 10:41:42 +00:00
|
|
|
let indices: Vec<u8> = vec![0, 1, 2, 1, 2, 3];
|
2021-11-03 18:17:07 +00:00
|
|
|
|
|
|
|
let pos_buffer = gl.create_buffer()?;
|
|
|
|
gl.bind_buffer(glow::ARRAY_BUFFER, Some(pos_buffer));
|
|
|
|
gl.buffer_data_u8_slice(
|
|
|
|
glow::ARRAY_BUFFER,
|
2022-01-15 12:59:52 +00:00
|
|
|
bytemuck::cast_slice(&positions),
|
2021-11-03 18:17:07 +00:00
|
|
|
glow::STATIC_DRAW,
|
|
|
|
);
|
|
|
|
|
|
|
|
let a_pos_loc = gl
|
|
|
|
.get_attrib_location(program, "a_pos")
|
|
|
|
.ok_or_else(|| "failed to get location of a_pos".to_string())?;
|
2022-03-22 22:11:27 +00:00
|
|
|
let vao = crate::vao::VertexArrayObject::new(
|
|
|
|
&gl,
|
|
|
|
pos_buffer,
|
|
|
|
vec![BufferInfo {
|
|
|
|
location: a_pos_loc,
|
|
|
|
vector_size: 2,
|
|
|
|
data_type: glow::FLOAT,
|
|
|
|
normalized: false,
|
|
|
|
stride: 0,
|
|
|
|
offset: 0,
|
|
|
|
}],
|
|
|
|
);
|
2021-11-03 18:17:07 +00:00
|
|
|
|
|
|
|
let index_buffer = gl.create_buffer()?;
|
|
|
|
gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(index_buffer));
|
|
|
|
gl.buffer_data_u8_slice(glow::ELEMENT_ARRAY_BUFFER, &indices, glow::STATIC_DRAW);
|
|
|
|
|
|
|
|
gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, None);
|
2022-03-22 15:04:06 +00:00
|
|
|
check_for_gl_error!(&gl, "post process initialization");
|
2021-11-03 18:17:07 +00:00
|
|
|
|
|
|
|
Ok(PostProcess {
|
2022-03-14 12:25:11 +00:00
|
|
|
gl,
|
2021-11-03 18:17:07 +00:00
|
|
|
pos_buffer,
|
|
|
|
index_buffer,
|
2022-03-22 22:11:27 +00:00
|
|
|
vao,
|
2021-11-03 18:17:07 +00:00
|
|
|
is_webgl_1,
|
2022-04-15 10:41:42 +00:00
|
|
|
color_texture,
|
|
|
|
depth_renderbuffer,
|
2021-11-03 18:17:07 +00:00
|
|
|
texture_size: (width, height),
|
|
|
|
fbo,
|
|
|
|
program,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-03-14 12:25:11 +00:00
|
|
|
pub(crate) unsafe fn begin(&mut self, width: i32, height: i32) {
|
2021-11-03 18:17:07 +00:00
|
|
|
if (width, height) != self.texture_size {
|
2022-04-15 10:41:42 +00:00
|
|
|
self.gl
|
|
|
|
.bind_texture(glow::TEXTURE_2D, Some(self.color_texture));
|
2022-03-14 12:25:11 +00:00
|
|
|
self.gl.pixel_store_i32(glow::UNPACK_ALIGNMENT, 1);
|
2021-11-03 18:17:07 +00:00
|
|
|
let (internal_format, format) = if self.is_webgl_1 {
|
|
|
|
(glow::SRGB_ALPHA, glow::SRGB_ALPHA)
|
|
|
|
} else {
|
|
|
|
(glow::SRGB8_ALPHA8, glow::RGBA)
|
|
|
|
};
|
2022-03-14 12:25:11 +00:00
|
|
|
self.gl.tex_image_2d(
|
2021-11-03 18:17:07 +00:00
|
|
|
glow::TEXTURE_2D,
|
|
|
|
0,
|
|
|
|
internal_format as i32,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
0,
|
|
|
|
format,
|
|
|
|
glow::UNSIGNED_BYTE,
|
|
|
|
None,
|
|
|
|
);
|
2022-03-14 12:25:11 +00:00
|
|
|
self.gl.bind_texture(glow::TEXTURE_2D, None);
|
2022-04-15 10:41:42 +00:00
|
|
|
|
|
|
|
if let Some(depth_renderbuffer) = self.depth_renderbuffer {
|
|
|
|
self.gl
|
|
|
|
.bind_renderbuffer(glow::RENDERBUFFER, Some(depth_renderbuffer));
|
|
|
|
self.gl.renderbuffer_storage(
|
|
|
|
glow::RENDERBUFFER,
|
|
|
|
glow::DEPTH_COMPONENT16,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
);
|
|
|
|
self.gl.bind_renderbuffer(glow::RENDERBUFFER, None);
|
|
|
|
}
|
|
|
|
|
2021-11-03 18:17:07 +00:00
|
|
|
self.texture_size = (width, height);
|
|
|
|
}
|
|
|
|
|
2022-03-22 15:04:06 +00:00
|
|
|
check_for_gl_error!(&self.gl, "PostProcess::begin");
|
2021-11-03 18:17:07 +00:00
|
|
|
}
|
|
|
|
|
2022-03-14 12:25:11 +00:00
|
|
|
pub(crate) unsafe fn bind(&self) {
|
|
|
|
self.gl.bind_framebuffer(glow::FRAMEBUFFER, Some(self.fbo));
|
2022-04-15 10:41:42 +00:00
|
|
|
|
|
|
|
self.gl.framebuffer_texture_2d(
|
|
|
|
glow::FRAMEBUFFER,
|
|
|
|
glow::COLOR_ATTACHMENT0,
|
|
|
|
glow::TEXTURE_2D,
|
|
|
|
Some(self.color_texture),
|
|
|
|
0,
|
|
|
|
);
|
|
|
|
|
|
|
|
self.gl.framebuffer_renderbuffer(
|
|
|
|
glow::FRAMEBUFFER,
|
|
|
|
glow::DEPTH_ATTACHMENT,
|
|
|
|
glow::RENDERBUFFER,
|
|
|
|
self.depth_renderbuffer,
|
|
|
|
);
|
|
|
|
|
|
|
|
check_for_gl_error!(&self.gl, "PostProcess::bind");
|
2022-03-14 12:25:11 +00:00
|
|
|
}
|
2021-11-03 18:17:07 +00:00
|
|
|
|
2022-03-14 12:25:11 +00:00
|
|
|
pub(crate) unsafe fn end(&self) {
|
|
|
|
self.gl.bind_framebuffer(glow::FRAMEBUFFER, None);
|
|
|
|
self.gl.disable(glow::SCISSOR_TEST);
|
|
|
|
|
|
|
|
self.gl.use_program(Some(self.program));
|
|
|
|
|
|
|
|
self.gl.active_texture(glow::TEXTURE0);
|
2022-04-15 10:41:42 +00:00
|
|
|
self.gl
|
|
|
|
.bind_texture(glow::TEXTURE_2D, Some(self.color_texture));
|
2022-03-14 12:25:11 +00:00
|
|
|
let u_sampler_loc = self
|
|
|
|
.gl
|
|
|
|
.get_uniform_location(self.program, "u_sampler")
|
|
|
|
.unwrap();
|
|
|
|
self.gl.uniform_1_i32(Some(&u_sampler_loc), 0);
|
2022-03-22 22:11:27 +00:00
|
|
|
self.vao.bind(&self.gl);
|
2022-03-14 12:25:11 +00:00
|
|
|
|
|
|
|
self.gl
|
|
|
|
.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(self.index_buffer));
|
|
|
|
self.gl
|
|
|
|
.draw_elements(glow::TRIANGLES, 6, glow::UNSIGNED_BYTE, 0);
|
2022-03-22 22:11:27 +00:00
|
|
|
self.vao.unbind(&self.gl);
|
2022-03-14 12:25:11 +00:00
|
|
|
self.gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, None);
|
|
|
|
self.gl.bind_texture(glow::TEXTURE_2D, None);
|
|
|
|
self.gl.use_program(None);
|
2022-03-22 15:04:06 +00:00
|
|
|
|
|
|
|
check_for_gl_error!(&self.gl, "PostProcess::end");
|
2021-11-03 18:17:07 +00:00
|
|
|
}
|
2021-12-28 13:24:59 +00:00
|
|
|
|
2022-03-14 12:25:11 +00:00
|
|
|
pub(crate) unsafe fn destroy(&self) {
|
|
|
|
self.gl.delete_buffer(self.pos_buffer);
|
|
|
|
self.gl.delete_buffer(self.index_buffer);
|
|
|
|
self.gl.delete_program(self.program);
|
|
|
|
self.gl.delete_framebuffer(self.fbo);
|
2022-04-15 10:41:42 +00:00
|
|
|
self.gl.delete_texture(self.color_texture);
|
|
|
|
if let Some(depth_renderbuffer) = self.depth_renderbuffer {
|
|
|
|
self.gl.delete_renderbuffer(depth_renderbuffer);
|
|
|
|
}
|
2021-11-03 18:17:07 +00:00
|
|
|
}
|
|
|
|
}
|