Skip to main content

lumen_engine/node/processing/
alpha_premultiply.rs

1use crate::node::{Deferred, NodeId, NodeParamEvalContext, NodeParams, PortRef};
2
3use crate::gpu::{
4    AlphaMode, BoundFrame, CompiledOutput, FrameBindContext, GpuCompileNode, GpuCompiledNode,
5    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::Delegate)]
12pub struct AlphaPremultiplyParams {
13    /// Alpha conversion mode.
14    #[meta(format = "alpha_premultiply_mode")]
15    pub mode: String,
16}
17
18impl Default for AlphaPremultiplyParams {
19    fn default() -> Self {
20        Self {
21            mode: "premultiply".to_string(),
22        }
23    }
24}
25
26/// Converts raster alpha between premultiplied and unpremultiplied representations.
27#[derive(Debug, Clone, lumen_macros::Node)]
28#[node(
29    kind = "alpha_premultiply",
30    name = "Alpha Premultiply",
31    category = "processing"
32)]
33pub struct AlphaPremultiply {
34    pub id: NodeId,
35    #[params]
36    pub params: AlphaPremultiplyParamsDelegate,
37
38    #[input()]
39    pub source: PortRef,
40}
41
42impl Default for AlphaPremultiply {
43    fn default() -> Self {
44        Self {
45            id: NodeId::new(0),
46            params: AlphaPremultiplyParamsDelegate::default(),
47            source: PortRef::empty(),
48        }
49    }
50}
51
52#[derive(Debug, Clone)]
53struct CompiledAlphaPremultiply {
54    node_id: NodeId,
55    params: AlphaPremultiplyParamsDelegate,
56    buffer: lumen_gpu::BufferId,
57}
58
59impl GpuCompiledNode for CompiledAlphaPremultiply {
60    fn node_id(&self) -> NodeId {
61        self.node_id
62    }
63
64    fn bind(&self, ctx: &FrameBindContext<'_>, bound: &mut BoundFrame) -> crate::Result<()> {
65        let evaluated = self.params.eval(&NodeParamEvalContext {
66            node_id: self.node_id,
67            expr: &ctx.expr_context(self.node_id, "params"),
68        })?;
69        let gpu_params = compiler::AlphaPremultiplyParams {
70            values: [
71                compiler::alpha_operation(self.node_id, &evaluated.mode)?,
72                0.0,
73                0.0,
74                0.0,
75            ],
76        };
77        bound.write_buffer(self.buffer, 0, bytemuck::bytes_of(&gpu_params));
78        Ok(())
79    }
80}
81
82impl GpuCompileNode for AlphaPremultiply {
83    fn compile_gpu(
84        &self,
85        ctx: &mut crate::gpu::CompileContext<'_>,
86        port: &PortRef,
87    ) -> crate::Result<CompiledOutput> {
88        let metadata = match &self.params.mode {
89            Deferred::Value(mode) if compiler::alpha_operation(self.id, mode)? < 0.5 => {
90                Some(AlphaMode::Premultiplied)
91            }
92            Deferred::Value(mode) if compiler::alpha_operation(self.id, mode)? >= 0.5 => {
93                Some(AlphaMode::Unpremultiplied)
94            }
95            _ => None,
96        };
97        let (source, texture, params) = ctx.compile_unary_filter(
98            self.id,
99            &self.source,
100            port,
101            "alpha-premultiply",
102            SHADER,
103            std::mem::size_of::<compiler::AlphaPremultiplyParams>() as u64,
104        )?;
105        ctx.register_compiled_node(CompiledAlphaPremultiply {
106            node_id: self.id,
107            params: self.params.clone(),
108            buffer: params,
109        });
110
111        let mut output_metadata = source.metadata;
112        if let Some(alpha_mode) = metadata {
113            output_metadata.alpha_mode = alpha_mode;
114        }
115        Ok(CompiledOutput::Raster(RasterHandle {
116            texture,
117            domain: source.domain,
118            metadata: output_metadata,
119        }))
120    }
121}