use crate::{
core::{algebra::Vector2, math::Rect, sstorage::ImmutableString},
graphics::{
error::FrameworkError,
framebuffer::{Attachment, GpuFrameBuffer},
geometry_buffer::GpuGeometryBuffer,
gpu_texture::{GpuTexture, PixelKind},
server::GraphicsServer,
},
renderer::{
cache::{
shader::{binding, property, PropertyGroup, RenderMaterial},
uniform::UniformBufferCache,
},
make_viewport_matrix,
resources::RendererResources,
RenderPassStatistics,
},
};
pub struct GaussianBlur {
h_framebuffer: GpuFrameBuffer,
v_framebuffer: GpuFrameBuffer,
width: usize,
height: usize,
}
fn create_framebuffer(
server: &dyn GraphicsServer,
name: &str,
width: usize,
height: usize,
pixel_kind: PixelKind,
) -> Result<GpuFrameBuffer, FrameworkError> {
server.create_frame_buffer(
None,
vec![Attachment::color(
server.create_2d_render_target(name, pixel_kind, width, height)?,
)],
)
}
impl GaussianBlur {
pub fn new(
server: &dyn GraphicsServer,
width: usize,
height: usize,
pixel_kind: PixelKind,
) -> Result<Self, FrameworkError> {
Ok(Self {
h_framebuffer: create_framebuffer(server, "HBlur", width, height, pixel_kind)?,
v_framebuffer: create_framebuffer(server, "VBlur", width, height, pixel_kind)?,
width,
height,
})
}
fn h_blurred(&self) -> &GpuTexture {
&self.h_framebuffer.color_attachments()[0].texture
}
pub fn result(&self) -> &GpuTexture {
&self.v_framebuffer.color_attachments()[0].texture
}
pub(crate) fn render(
&self,
server: &dyn GraphicsServer,
quad: &GpuGeometryBuffer,
input: &GpuTexture,
uniform_buffer_cache: &mut UniformBufferCache,
renderer_resources: &RendererResources,
) -> Result<RenderPassStatistics, FrameworkError> {
let _debug_scope = server.begin_scope("GaussianBlur");
let mut stats = RenderPassStatistics::default();
let viewport = Rect::new(0, 0, self.width as i32, self.height as i32);
let inv_size = Vector2::new(1.0 / self.width as f32, 1.0 / self.height as f32);
let wvp = make_viewport_matrix(viewport);
for (image, framebuffer, horizontal) in [
(input, &self.h_framebuffer, true),
(self.h_blurred(), &self.v_framebuffer, false),
] {
let properties = PropertyGroup::from([
property("worldViewProjection", &wvp),
property("pixelSize", &inv_size),
property("horizontal", &horizontal),
]);
let material = RenderMaterial::from([
binding("image", (image, &renderer_resources.nearest_clamp_sampler)),
binding("properties", &properties),
]);
stats += renderer_resources.shaders.gaussian_blur.run_pass(
1,
&ImmutableString::new("Primary"),
framebuffer,
quad,
viewport,
&material,
uniform_buffer_cache,
Default::default(),
None,
)?;
}
Ok(stats)
}
}