mod copy;
mod fog;
mod fullscreen;
mod fxaa;
pub use copy::CopyEffect;
pub use fog::{FogEffect, FogMode};
pub use fullscreen::FullscreenQuad;
pub use fxaa::FxaaEffect;
use crate::context::WgpuContext;
use crate::core::Texture2D;
pub trait Effect {
fn apply(
&self,
ctx: &WgpuContext,
encoder: &mut wgpu::CommandEncoder,
input: &wgpu::TextureView,
output: &wgpu::TextureView,
);
}
pub struct EffectChain {
effects: Vec<Box<dyn Effect>>,
intermediate_textures: Vec<Texture2D>,
}
impl EffectChain {
pub fn new() -> Self {
Self {
effects: Vec::new(),
intermediate_textures: Vec::new(),
}
}
pub fn add(&mut self, effect: Box<dyn Effect>) {
self.effects.push(effect);
}
pub fn ensure_textures(
&mut self,
ctx: &WgpuContext,
width: u32,
height: u32,
format: wgpu::TextureFormat,
) {
let needed = if self.effects.len() > 1 {
self.effects.len() - 1
} else {
0
};
while self.intermediate_textures.len() < needed {
let tex = Texture2D::new(
ctx,
width,
height,
format,
wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT,
Some(&format!(
"effect chain intermediate {}",
self.intermediate_textures.len()
)),
);
self.intermediate_textures.push(tex);
}
for tex in &mut self.intermediate_textures {
let (w, h) = tex.size();
if w != width || h != height {
*tex = Texture2D::new(
ctx,
width,
height,
format,
wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT,
Some("effect chain intermediate"),
);
}
}
}
pub fn apply(
&self,
ctx: &WgpuContext,
encoder: &mut wgpu::CommandEncoder,
input: &wgpu::TextureView,
output: &wgpu::TextureView,
) {
if self.effects.is_empty() {
return;
}
if self.effects.len() == 1 {
self.effects[0].apply(ctx, encoder, input, output);
return;
}
let mut current_input = input;
for (i, effect) in self.effects.iter().enumerate() {
let is_last = i == self.effects.len() - 1;
let current_output = if is_last {
output
} else {
self.intermediate_textures[i].view()
};
effect.apply(ctx, encoder, current_input, current_output);
if !is_last {
current_input = self.intermediate_textures[i].view();
}
}
}
pub fn len(&self) -> usize {
self.effects.len()
}
pub fn is_empty(&self) -> bool {
self.effects.is_empty()
}
pub fn clear(&mut self) {
self.effects.clear();
}
}
impl Default for EffectChain {
fn default() -> Self {
Self::new()
}
}