Skip to main content

lumen_engine/node/processing/
alpha_premultiply.rs

1use crate::node::{NodeId, NodeProperty, PortRef};
2
3use crate::gpu::{
4    AlphaMode, BoundFrame, CompiledOutput, FrameBindContext, FrameBinding, GpuCompileNode,
5    GpuFrameBindNode, RasterHandle, compiler,
6};
7
8pub(crate) const SHADER: &str = include_str!("alpha_premultiply.wgsl");
9
10/// Converts raster alpha between premultiplied and unpremultiplied representations.
11#[derive(Debug, Clone, lumen_macros::Node)]
12#[node(
13    kind = "alpha_premultiply",
14    name = "Alpha Premultiply",
15    category = "processing"
16)]
17pub struct AlphaPremultiply {
18    pub id: NodeId,
19    /// Alpha conversion mode.
20    #[property(kind = "string", format = "alpha_premultiply_mode")]
21    pub mode: NodeProperty,
22    #[input()]
23    pub source: PortRef,
24}
25
26impl Default for AlphaPremultiply {
27    fn default() -> Self {
28        Self {
29            id: NodeId::new(0),
30            mode: NodeProperty::String("premultiply".to_string()),
31            source: PortRef::empty(),
32        }
33    }
34}
35
36impl GpuCompileNode for AlphaPremultiply {
37    fn compile_gpu(
38        &self,
39        ctx: &mut crate::gpu::CompileContext<'_>,
40        port: &PortRef,
41    ) -> crate::Result<CompiledOutput> {
42        let metadata = match &self.mode {
43            NodeProperty::String(mode) if compiler::alpha_operation(self.id, mode)? < 0.5 => {
44                Some(AlphaMode::Premultiplied)
45            }
46            NodeProperty::String(mode) if compiler::alpha_operation(self.id, mode)? >= 0.5 => {
47                Some(AlphaMode::Unpremultiplied)
48            }
49            _ => None,
50        };
51        let (source, texture, params) = ctx.compile_unary_filter(
52            self.id,
53            &self.source,
54            port,
55            "alpha-premultiply",
56            SHADER,
57            std::mem::size_of::<compiler::AlphaPremultiplyParams>() as u64,
58        )?;
59        ctx.push_frame_binding(FrameBinding::AlphaPremultiply {
60            node_id: self.id,
61            mode: self.mode.clone(),
62            buffer: params,
63        });
64
65        let mut output_metadata = source.metadata;
66        if let Some(alpha_mode) = metadata {
67            output_metadata.alpha_mode = alpha_mode;
68        }
69        Ok(CompiledOutput::Raster(RasterHandle {
70            texture,
71            domain: source.domain,
72            metadata: output_metadata,
73        }))
74    }
75}
76
77impl GpuFrameBindNode for AlphaPremultiply {
78    fn bind_gpu_frame(
79        &self,
80        ctx: &FrameBindContext<'_>,
81        binding: &FrameBinding,
82        bound: &mut BoundFrame,
83    ) -> crate::Result<()> {
84        let FrameBinding::AlphaPremultiply {
85            node_id,
86            mode,
87            buffer,
88        } = binding
89        else {
90            return Ok(());
91        };
92        let mode = mode.resolve_string(*node_id, "mode", &ctx.expr_context(*node_id, "mode"))?;
93        let params = compiler::AlphaPremultiplyParams {
94            values: [compiler::alpha_operation(*node_id, &mode)?, 0.0, 0.0, 0.0],
95        };
96        bound.write_buffer(*buffer, 0, bytemuck::bytes_of(&params));
97        Ok(())
98    }
99}