use std::borrow::Borrow;
use rinecs::{SystemThreadLocal, EntitiesThreadLocal, ResourcesThreadLocal, system_thread_local};
use crate::renderer::{
resources::{ScreenRenderBuffer, RenderStage},
};
use rin_graphics::{self as graphics, Mvp, CameraExt};
use rin_window::{Window, WindowExt};
use rin_gl::{self as gl, Renderer2d, fbo::{ColorAttachment, DepthAttachment}};
use rin_math::{pnt2, vec2, convert, Pnt2};
use rin_postpo as postprocessing;
use crate::DeferredScene;
use crate::transformation::Viewport;
use rin_util::LogErr;
pub use postprocessing::{Parameters, PostProcessing, BloomBlend, Tonemap};
pub struct Bundle{
parameters: Parameters,
format: Option<gl::fbo::ColorFormat>,
}
impl Bundle{
pub fn new_with_parameters(parameters: Parameters) -> Bundle {
Bundle{
parameters,
format: None,
}
}
pub fn new_with_format(format: gl::fbo::ColorFormat) -> Bundle {
let parameters = Parameters::default();
Bundle{
parameters,
format: Some(format),
}
}
pub fn new_with_format_and_parameters(format: gl::fbo::ColorFormat, parameters: Parameters) -> Bundle {
Bundle{
parameters,
format: Some(format),
}
}
pub fn new() -> Bundle {
let parameters = Parameters::default();
Bundle{
parameters,
format: None,
}
}
}
impl crate::Bundle for Bundle{
type Parameters = Parameters;
fn parameters(&self) -> Option<&Parameters> {
Some(&self.parameters)
}
fn name(&self) -> &str{
"postprocessing"
}
fn setup(self, world: &mut DeferredScene){
let postpo;
let translucent_blit_fbo;
{
let gl = world.resource::<gl::Renderer>().unwrap();
translucent_blit_fbo = gl.new_fbo().empty().unwrap();
let surface = world.resource::<ScreenRenderBuffer>()
.expect("Can't use postprocessing without a screen render buffer");
let format = self.format.unwrap_or_else(|| surface.color_format());
let (w, h) = (surface.width(), surface.height());
postpo = postprocessing::PostProcessing::new(&gl, w, h, format)
.log_err("Error creating post processing")
.expect("Error creating post processing");
}
world.add_system_thread_local(PostprocessingOpaqueSystem);
world.add_system_thread_local(PostprocessingTranslucentSystem{fbo: translucent_blit_fbo});
world.add_resource_thread_local(postpo);
world.add_resource_thread_local(self.parameters);
}
}
struct PostprocessingOpaqueSystem;
#[system_thread_local(name = "ssao")]
#[needs(
"ScreenRenderBuffer",
"crate::render_stage::RenderSurfaceOpaque",
"crate::render_stage::AfterRenderSurfaceOpaque",
rin_postpo::Parameters
)]
#[updates("postprocessing::PostProcessing", "crate::render_stage::PostprocessingOpaque")]
#[reads(gl::Renderer, dyn CameraExt + Send)]
#[gpu_stats]
impl SystemThreadLocal for PostprocessingOpaqueSystem {
fn run(&mut self, _entities: EntitiesThreadLocal, resources: ResourcesThreadLocal){
let glin = resources.get::<gl::Renderer<'static>>().unwrap();
if let Some(fbo) = resources.get::<ScreenRenderBuffer>(){
#[cfg(glsl_debug)]
let postpro = {
let mut postpro = resources.get_mut::<postprocessing::PostProcessing>().unwrap();
postpro.update();
postpro
};
#[cfg(not(glsl_debug))]
let postpro = resources.get::<postprocessing::PostProcessing>().unwrap();
#[cfg(gl_debug_groups)]
let _debug_group = glin.new_debug_group(0, "Postprocessing opaque");
if let glin::fbo::ColorAttachment::TextureLevel(color, _) = fbo.color_attachment() {
if let Some(glin::fbo::ColorAttachment::TextureLevel(ambient, _)) = fbo.separate_ambient_attachment() {
if let DepthAttachment::TextureLevel(depth, _) = fbo.depth_attachment(){
let position = if let Some(ColorAttachment::TextureLevel(position, _)) = fbo.position_attachment() {
Some(postprocessing::SSAOPosition::Position(
depth,
position
))
}else if let Some(ColorAttachment::TextureLevel(linear_depth, _)) = fbo.linear_depth_attachment() {
Some(postprocessing::SSAOPosition::FromLinearDepth(
depth,
linear_depth
))
}else{
Some(postprocessing::SSAOPosition::FromDepth(depth))
};
let normals = fbo.normals_attachment().and_then(|normals|
if let glin::fbo::ColorAttachment::TextureLevel(normals, _) = normals{
Some(normals)
}else{
None
});
let camera = resources.as_trait::<dyn CameraExt + Send>().unwrap();
let parameters = resources.get::<Parameters>().unwrap();
postpro.process_until_ssao(
&glin,
&*camera,
color,
position,
normals,
ambient,
¶meters).log_err("Error postprocessing: ").unwrap();
}else{
log::error!("Trying to postprocess on render buffer without a texture depth attachment");
}
}
}else{
log::error!("Trying to postprocess on render buffer without color attachment");
panic!("Trying to postprocess on render buffer without color attachment")
}
}else{
log::error!("Trying to postprocess on without render buffer.
You probably need to create the renderer bundle using new_with_render_surface");
panic!("Trying to postprocess on without render buffer.
You probably need to create the renderer bundle using new_with_render_surface");
}
}
}
struct PostprocessingTranslucentSystem{
fbo: gl::Fbo<(),()>,
}
#[system_thread_local(name = "postprocessing")]
#[needs(
"ScreenRenderBuffer",
"crate::render_stage::RenderSurfaceOpaque",
"crate::render_stage::AfterRenderSurfaceOpaque",
"crate::render_stage::PostprocessingOpaque",
"crate::render_stage::AfterPostprocessingOpaque",
"crate::render_stage::RenderSurfaceTranslucent",
"crate::render_stage::AfterRenderSurfaceTranslucent",
rin_postpo::Parameters,
dyn CameraExt + Send,
Viewport
)]
#[updates("postprocessing::PostProcessing", "crate::render_stage::Postprocessing")]
#[reads(gl::Renderer)]
#[gpu_stats]
impl SystemThreadLocal for PostprocessingTranslucentSystem {
fn run(&mut self, _entities: EntitiesThreadLocal, resources: ResourcesThreadLocal){
let glin = resources.get::<gl::Renderer<'static>>().unwrap();
let postpro = resources.get_mut::<postprocessing::PostProcessing>().unwrap();
if let Some(render_surface) = resources.get::<ScreenRenderBuffer>(){
if render_surface.last_stage() == RenderStage::Translucent
|| render_surface.last_stage() == RenderStage::AfterTranslucent
{
if let glin::fbo::ColorAttachment::TextureLevel(color, _) = render_surface.color_attachment_force_resolve() {
#[cfg(gl_debug_groups)]
let debug_group = glin.new_debug_group(0, "Surface resolve");
let fbo_color = postpro.ssao_color_attachment();
let fbo = self.fbo
.with::<_, gl::fbo::DepthAttachment,_>(vec![fbo_color], None)
.unwrap();
let glin = resources.get::<gl::Renderer<'static>>().unwrap();
let glin = glin.with_fbo(&fbo);
let glin = glin.with_properties(&[
glin::Property::Blend(true),
glin::Property::BlendFuncSeparate(
gl::ONE,
gl::ONE_MINUS_SRC_ALPHA,
gl::ZERO,
gl::ONE),
]);
let glin = glin.with_mvp(Mvp::ortho_top_left(fbo.viewport().into()));
glin.draw_pos(color, &Pnt2::origin());
}
}
let depth = if let Some(ColorAttachment::TextureLevel(linear_depth, _)) = render_surface.linear_depth_attachment() {
Some(postprocessing::DofDepth::LinearDepth(
linear_depth
))
}else if let DepthAttachment::TextureLevel(depth, _) = render_surface.depth_attachment(){
Some(postprocessing::DofDepth::Depth(depth))
}else{
None
};
let parameters = resources.get::<Parameters>().unwrap();
let camera = resources.as_trait::<dyn CameraExt + Send>().unwrap();
let viewport = resources.get::<Viewport>().unwrap();
if render_surface.separate_ambient_attachment().is_some() {
#[cfg(gl_debug_groups)]
let debug_group = glin.new_debug_group(0, "Postprocessing translucent");
if let Err(err) = postpro.process_after_ssao(
&glin,
&*camera,
&viewport,
postpro.ssao_color_texture(),
depth,
¶meters)
{
panic!("Error on postprocessing {}", err);
}
}else{
if let glin::fbo::ColorAttachment::TextureLevel(color, _) = render_surface.color_attachment() {
if let Err(err) = postpro.process_after_ssao(
&glin,
&*camera,
&viewport,
color,
depth,
¶meters)
{
panic!("Error on postprocessing {}", err);
}
}else{
log::error!("Trying to postprocess on render buffer without color attachment");
panic!("Trying to postprocess on render buffer without color attachment")
}
}
}else{
log::error!("Trying to postprocess on without render buffer.
You probably need to create the renderer bundle using new_with_render_surface");
panic!("Trying to postprocess on without render buffer.
You probably need to create the renderer bundle using new_with_render_surface");
}
let draw_stages = false;
if draw_stages {
let window = resources.get::<Window>().unwrap();
let viewport = window.viewport();
let glin = glin.with_mvp(graphics::Mvp::ortho_top_left(viewport));
let parameters = resources.get::<Parameters>().unwrap();
let mut pos = pnt2(window.width() - 266, 10);
let ratio = postpro.ssao_texture().width() as f32 / postpro.ssao_texture().height() as f32;
if *parameters.fxaa.borrow() {
glin.draw_size(postpro.fxaa_texture(), &convert(pos), &vec2(256., 256. / ratio));
pos += vec2(0, (256. / ratio) as i32 + 10);
if pos.y + 256 > window.height() {
pos.x -= 266;
pos.y = 10;
}
}
if *parameters.bloom.borrow() {
}
if *parameters.ssao.borrow() {
glin.draw_size(postpro.ssao_texture(), &convert(pos), &vec2(256., 256. / ratio));
pos += vec2(0, (256. / ratio) as i32 + 10);
if pos.y + 256 > window.height() {
pos.x -= 266;
pos.y = 10;
}
glin.draw_size(postpro.ssao_blur_texture(), &convert(pos), &vec2(256., 256. / ratio));
pos += vec2(0, (256. / ratio) as i32 + 10);
if pos.y + 256 > window.height() {
pos.x -= 266;
pos.y = 10;
}
glin.draw_size(postpro.ssao_color_texture(), &convert(pos), &vec2(256., 256. / ratio));
pos += vec2(0, (256. / ratio) as i32 + 10);
if pos.y + 256 > window.height() {
pos.x -= 266;
pos.y = 10;
}
}
}
}
}