use crate::core::*;
use std::sync::Mutex;
use std::mem::swap;
use std::cmp::{min, max};
pub struct Bloom {
targets : [[Texture; 5]; 2],
blur_program : Mutex<Program>,
combine_program : Program,
pub iterations : u8,
pub iter_blend : BlendMode,
pub draw_blend : BlendMode,
pub draw_color : Color,
pub clear : bool,
pub vertical : u8,
pub horizontal : u8,
}
impl Postprocessor for Bloom {
type T = ();
fn target(self: &Self) -> &Texture {
if self.clear {
let horizontal = min(self.horizontal as usize, self.targets[0].len());
let vertical = min(self.vertical as usize, self.targets[0].len());
let spread = max(horizontal, vertical);
for i in 0..spread as usize {
self.targets[1][i].clear(Color::TRANSPARENT);
}
self.targets[0][0].clear(Color::TRANSPARENT);
}
&self.targets[0][0]
}
fn process(self: &Self, renderer: &Renderer, _: &Self::T) {
let horizontal = min(self.horizontal as usize, self.targets[0].len());
let vertical = min(self.vertical as usize, self.targets[0].len());
let spread = max(horizontal, vertical);
for i in 1..spread as usize {
renderer.render_to(&self.targets[0][i], || {
renderer.copy_from(&self.targets[0][i-1], TextureFilter::Linear);
});
}
let mut blur = self.blur_program.lock().unwrap();
let blur = blur.deref_mut();
let mut dst = 1;
let mut src = 0;
for _ in 0..self.iterations {
if horizontal > 0 {
blur.set_uniform("horizontal", &true);
for i in 0..spread as usize {
renderer.render_to(&self.targets[dst][i], || {
let fill = renderer.fill().blendmode(self.iter_blend).texture(&self.targets[src][i]);
if i < horizontal {
fill.program(&blur).draw();
} else {
fill.draw();
}
});
}
swap(&mut dst, &mut src);
}
if vertical > 0 {
blur.set_uniform("horizontal", &false);
for i in 0..spread as usize {
renderer.render_to(&self.targets[dst][i], || {
let fill = renderer.fill().blendmode(self.iter_blend).texture(&self.targets[src][i]);
if i < vertical {
fill.program(&blur).draw();
} else {
fill.draw();
}
});
}
swap(&mut dst, &mut src);
}
}
}
fn draw(self: &Self, renderer: &Renderer, _: &Self::T) {
renderer.fill().blendmode(self.draw_blend).color(self.draw_color).program(&self.combine_program).draw();
}
}
impl Bloom {
pub fn new<T>(context: &Context, dimensions: T, divider_factor: u32) -> Self where Point2<u32>: From<T> {
let dimensions = Point2::<u32>::from(dimensions);
let blur_program = Program::from_string(&context, include_str!("../../shader/postprocess/blur.wgsl")).unwrap();
let mut combine_program = Program::from_string(&context, include_str!("../../shader/postprocess/combine.wgsl")).unwrap();
let targets = Self::create_targets(context, dimensions, divider_factor);
let max_ops = targets[0].len();
combine_program.set_uniform("sample0", &targets[0][0]);
combine_program.set_uniform("sample1", &targets[0][1]);
combine_program.set_uniform("sample2", &targets[0][2]);
combine_program.set_uniform("sample3", &targets[0][3]);
combine_program.set_uniform("sample4", &targets[0][4]);
Bloom {
blur_program : Mutex::new(blur_program),
combine_program : combine_program,
targets : targets,
iterations : 3,
iter_blend : blendmodes::COPY,
draw_blend : blendmodes::ADD,
draw_color : Color::WHITE,
clear : true,
vertical : max_ops as u8,
horizontal : max_ops as u8,
}
}
pub fn rebuild<T>(self: &mut Self, context: &Context, dimensions: T, divider_factor: u32) where Point2<u32>: From<T> {
let targets = Self::create_targets(context, Point2::<u32>::from(dimensions), divider_factor);
self.combine_program.set_uniform("sample0", &targets[0][0]);
self.combine_program.set_uniform("sample1", &targets[0][1]);
self.combine_program.set_uniform("sample2", &targets[0][2]);
self.combine_program.set_uniform("sample3", &targets[0][3]);
self.combine_program.set_uniform("sample4", &targets[0][4]);
self.targets = targets;
}
fn create_targets(context: &Context, (width, height): Point2<u32>, divider_factor: u32) -> [[Texture; 5]; 2] {
let builder = Texture::builder(context).format(TextureFormat::F16F16F16F16);
let f0 = 1;
let f1 = f0 * divider_factor;
let f2 = f1 * divider_factor;
let f3 = f2 * divider_factor;
let f4 = f3 * divider_factor;
[ [
builder.clone().dimensions((width / f0, height / f0)).build().unwrap(),
builder.clone().dimensions((width / f1, height / f1)).build().unwrap(),
builder.clone().dimensions((width / f2, height / f2)).build().unwrap(),
builder.clone().dimensions((width / f3, height / f3)).build().unwrap(),
builder.clone().dimensions((width / f4, height / f4)).build().unwrap(),
], [
builder.clone().dimensions((width / f0, height / f0)).build().unwrap(),
builder.clone().dimensions((width / f1, height / f1)).build().unwrap(),
builder.clone().dimensions((width / f2, height / f2)).build().unwrap(),
builder.clone().dimensions((width / f3, height / f3)).build().unwrap(),
builder.clone().dimensions((width / f4, height / f4)).build().unwrap(),
] ]
}
}