enigma_3d/postprocessing/
bloom.rs

1use glium::{IndexBuffer, Surface, Texture2d, uniform, VertexBuffer};
2use glium::framebuffer::SimpleFrameBuffer;
3use glium::glutin::surface::WindowSurface;
4use glium::texture::DepthTexture2d;
5use crate::geometry::Vertex;
6use crate::postprocessing::PostProcessingEffect;
7use crate::{AppState, postprocessing, resources, shader};
8
9pub struct Bloom {
10    pub threshold: f32,
11    pub iterations: i32,
12    program_extract: glium::Program,
13    program_blur: glium::Program,
14    program_combine: glium::Program,
15    program_copy: glium::Program,
16}
17
18impl Bloom {
19    pub fn new(display: &glium::Display<WindowSurface>, threshold: f32, iterations: i32) -> Self {
20        let extract_shader = shader::Shader::from_strings(resources::post_processing_vertex(), resources::post_processing_bloom_extract_fragment(), None);
21        let blur_shader = shader::Shader::from_strings(resources::post_processing_vertex(), resources::post_processing_bloom_blur_fragment(), None);
22        let combine_shader = shader::Shader::from_strings(resources::post_processing_vertex(), resources::post_processing_bloom_combine_fragment(), None);
23        let program_extract = glium::Program::from_source(display, &extract_shader.get_vertex_shader(), &extract_shader.get_fragment_shader(), None).expect("Failed to compile shader program");
24        let program_blur = glium::Program::from_source(display, &blur_shader.get_vertex_shader(), &blur_shader.get_fragment_shader(), None).expect("Failed to compile shader program");
25        let program_combine = glium::Program::from_source(display, &combine_shader.get_vertex_shader(), &combine_shader.get_fragment_shader(), None).expect("Failed to compile shader program");
26        let program_copy = postprocessing::get_screen_program(&display);
27
28        Self {
29            program_extract,
30            program_blur,
31            program_combine,
32            program_copy,
33            threshold,
34            iterations,
35        }
36    }
37}
38
39impl PostProcessingEffect for Bloom {
40    fn render(&self, app_state: &AppState, vertex_buffer: &VertexBuffer<Vertex>, index_buffer: &IndexBuffer<u32>, target: &mut SimpleFrameBuffer, source: &Texture2d, _depth_texture: &DepthTexture2d, buffer_textures: &Vec<Texture2d>) {
41        // first create a temporary framebuffer to render the scene to and then use it as a texture
42        let mut work_framebuffer_1 = SimpleFrameBuffer::new(app_state.display.as_ref().unwrap(), &buffer_textures[0]).unwrap();
43        let mut work_framebuffer_2 = SimpleFrameBuffer::new(app_state.display.as_ref().unwrap(), &buffer_textures[1]).unwrap();
44        work_framebuffer_1.clear_color(0.0, 0.0, 0.0, 0.0);
45        work_framebuffer_2.clear_color(0.0, 0.0, 0.0, 0.0);
46
47        // creating copies of the incomming scene
48        let uniforms = uniform! {
49            scene: source.sampled()
50                .wrap_function(glium::uniforms::SamplerWrapFunction::Clamp)
51                .minify_filter(glium::uniforms::MinifySamplerFilter::LinearMipmapLinear)
52                .magnify_filter(glium::uniforms::MagnifySamplerFilter::Linear),
53        };
54        work_framebuffer_1.draw(vertex_buffer, index_buffer, &self.program_copy, &uniforms, &Default::default()).unwrap();
55        work_framebuffer_2.draw(vertex_buffer, index_buffer, &self.program_copy, &uniforms, &Default::default()).unwrap();
56
57        // extract the bright parts of the scene
58        let uniforms = uniform! {
59            scene: source.sampled()
60                .wrap_function(glium::uniforms::SamplerWrapFunction::Clamp)
61                .minify_filter(glium::uniforms::MinifySamplerFilter::LinearMipmapLinear)
62                .magnify_filter(glium::uniforms::MagnifySamplerFilter::Linear),
63            threshold: self.threshold,
64        };
65        work_framebuffer_1.draw(vertex_buffer, index_buffer, &self.program_extract, &uniforms, &Default::default()).unwrap();
66
67        // blur the bright parts of the scene
68        let uniforms = uniform! {
69            scene: buffer_textures[0].sampled()
70                .wrap_function(glium::uniforms::SamplerWrapFunction::Clamp)
71                .minify_filter(glium::uniforms::MinifySamplerFilter::LinearMipmapLinear)
72                .magnify_filter(glium::uniforms::MagnifySamplerFilter::Linear),
73            horizontal: true,
74            iterations: self.iterations,
75        };
76        work_framebuffer_2.draw(vertex_buffer, index_buffer, &self.program_blur, &uniforms, &Default::default()).unwrap();
77        work_framebuffer_1.clear_color(0.0, 0.0, 0.0, 0.0);
78
79        let uniforms = uniform! {
80            scene: buffer_textures[1].sampled()
81                .wrap_function(glium::uniforms::SamplerWrapFunction::Clamp)
82                .minify_filter(glium::uniforms::MinifySamplerFilter::LinearMipmapLinear)
83                .magnify_filter(glium::uniforms::MagnifySamplerFilter::Linear),
84            horizontal: false,
85            iterations: self.iterations,
86        };
87        work_framebuffer_1.draw(vertex_buffer, index_buffer, &self.program_blur, &uniforms, &Default::default()).unwrap();
88
89        // render to original framebuffer
90        let uniforms = uniform! {
91            scene: source.sampled()
92                .wrap_function(glium::uniforms::SamplerWrapFunction::Clamp)
93                .minify_filter(glium::uniforms::MinifySamplerFilter::LinearMipmapLinear)
94                .magnify_filter(glium::uniforms::MagnifySamplerFilter::Linear),
95            bloomBlur: buffer_textures[0].sampled()
96                .wrap_function(glium::uniforms::SamplerWrapFunction::Clamp)
97                .minify_filter(glium::uniforms::MinifySamplerFilter::LinearMipmapLinear)
98                .magnify_filter(glium::uniforms::MagnifySamplerFilter::Linear),
99        };
100        target.draw(vertex_buffer, index_buffer, &self.program_combine, &uniforms, &Default::default()).unwrap();
101    }
102}