lumen_engine/node/processing/
blur.rs1use crate::node::{NodeId, NodeProperty, PortRef};
2
3use crate::gpu::{
4 BoundFrame, CompiledOutput, FrameBindContext, FrameBinding, GpuCompileNode, GpuFrameBindNode,
5 RasterHandle, compiler,
6};
7
8pub(crate) const SHADER: &str = include_str!("blur.wgsl");
9
10#[derive(Debug, Clone, lumen_macros::Node)]
12#[node(kind = "blur", name = "Blur", category = "processing")]
13pub struct Blur {
14 pub id: NodeId,
15 #[property(kind = "float", min = 0, step = 0.5)]
17 pub radius: NodeProperty,
18 #[input()]
19 pub source: PortRef,
20}
21
22impl Default for Blur {
23 fn default() -> Self {
24 Self {
25 id: NodeId::new(0),
26 radius: NodeProperty::Float(4.0),
27 source: PortRef::empty(),
28 }
29 }
30}
31
32impl GpuCompileNode for Blur {
33 fn compile_gpu(
34 &self,
35 ctx: &mut crate::gpu::CompileContext<'_>,
36 port: &PortRef,
37 ) -> crate::Result<CompiledOutput> {
38 let (source, texture, params) = ctx.compile_unary_filter(
39 self.id,
40 &self.source,
41 port,
42 "blur",
43 SHADER,
44 std::mem::size_of::<compiler::BlurParams>() as u64,
45 )?;
46 ctx.push_frame_binding(FrameBinding::Blur {
47 node_id: self.id,
48 radius: self.radius.clone(),
49 buffer: params,
50 });
51 Ok(CompiledOutput::Raster(RasterHandle {
52 texture,
53 domain: source.domain,
54 metadata: source.metadata,
55 }))
56 }
57}
58
59impl GpuFrameBindNode for Blur {
60 fn bind_gpu_frame(
61 &self,
62 ctx: &FrameBindContext<'_>,
63 binding: &FrameBinding,
64 bound: &mut BoundFrame,
65 ) -> crate::Result<()> {
66 let FrameBinding::Blur {
67 node_id,
68 radius,
69 buffer,
70 } = binding
71 else {
72 return Ok(());
73 };
74 let radius = radius
75 .resolve_float(*node_id, "radius", &ctx.expr_context(*node_id, "radius"))?
76 .round()
77 .clamp(0.0, 32.0) as u32;
78 let params = compiler::BlurParams {
79 values: [radius, 0, 0, 0],
80 };
81 bound.write_buffer(*buffer, 0, bytemuck::bytes_of(¶ms));
82 Ok(())
83 }
84}