Skip to main content

lumen_engine/node/processing/
blur.rs

1use crate::node::{NodeId, NodeParamEvalContext, NodeParams, PortRef};
2
3use crate::gpu::{
4    BoundFrame, CompiledOutput, FrameBindContext, GpuCompileNode, GpuCompiledNode, RasterHandle,
5    compiler,
6};
7
8pub(crate) const SHADER: &str = include_str!("blur.wgsl");
9
10#[derive(Debug, Clone, lumen_macros::Delegate)]
11pub struct BlurParams {
12    /// Blur radius in pixels.
13    #[meta(min = 0, step = 0.5)]
14    pub radius: f64,
15}
16
17impl Default for BlurParams {
18    fn default() -> Self {
19        Self { radius: 4.0 }
20    }
21}
22
23/// Applies a simple box blur to a raster.
24#[derive(Debug, Clone, lumen_macros::Node)]
25#[node(kind = "blur", name = "Blur", category = "processing")]
26pub struct Blur {
27    pub id: NodeId,
28    #[params]
29    pub params: BlurParamsDelegate,
30    #[input()]
31    pub source: PortRef,
32}
33
34impl Default for Blur {
35    fn default() -> Self {
36        Self {
37            id: NodeId::new(0),
38            params: BlurParamsDelegate::default(),
39            source: PortRef::empty(),
40        }
41    }
42}
43
44#[derive(Debug, Clone)]
45struct CompiledBlur {
46    node_id: NodeId,
47    params: BlurParamsDelegate,
48    buffer: lumen_gpu::BufferId,
49}
50
51impl GpuCompiledNode for CompiledBlur {
52    fn node_id(&self) -> NodeId {
53        self.node_id
54    }
55
56    fn bind(&self, ctx: &FrameBindContext<'_>, bound: &mut BoundFrame) -> crate::Result<()> {
57        let params = self.params.eval(&NodeParamEvalContext {
58            node_id: self.node_id,
59            expr: &ctx.expr_context(self.node_id, "params"),
60        })?;
61        let radius = params.radius.round().clamp(0.0, 32.0) as u32;
62        let params = compiler::BlurParams {
63            values: [radius, 0, 0, 0],
64        };
65        bound.write_buffer(self.buffer, 0, bytemuck::bytes_of(&params));
66        Ok(())
67    }
68}
69
70impl GpuCompileNode for Blur {
71    fn compile_gpu(
72        &self,
73        ctx: &mut crate::gpu::CompileContext<'_>,
74        port: &PortRef,
75    ) -> crate::Result<CompiledOutput> {
76        let (source, texture, params) = ctx.compile_unary_filter(
77            self.id,
78            &self.source,
79            port,
80            "blur",
81            SHADER,
82            std::mem::size_of::<compiler::BlurParams>() as u64,
83        )?;
84        ctx.register_compiled_node(CompiledBlur {
85            node_id: self.id,
86            params: self.params.clone(),
87            buffer: params,
88        });
89        Ok(CompiledOutput::Raster(RasterHandle {
90            texture,
91            domain: source.domain,
92            metadata: source.metadata,
93        }))
94    }
95}