lumen_engine/node/processing/
levels.rs1use 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!("levels.wgsl");
9
10#[derive(Debug, Clone, lumen_macros::Delegate)]
12pub struct LevelsParams {
13 #[meta(min = 0, max = 1, step = 0.01)]
15 pub black_point: f64,
16 #[meta(min = 0, max = 1, step = 0.01)]
18 pub white_point: f64,
19 #[meta(min = 0.01, step = 0.01)]
21 pub gamma: f64,
22 #[meta(min = 0, max = 1, step = 0.01)]
24 pub output_black: f64,
25 #[meta(min = 0, max = 1, step = 0.01)]
27 pub output_white: f64,
28}
29
30impl Default for LevelsParams {
31 fn default() -> Self {
32 Self {
33 black_point: 0.0,
34 white_point: 1.0,
35 gamma: 1.0,
36 output_black: 0.0,
37 output_white: 1.0,
38 }
39 }
40}
41
42#[derive(Debug, Clone, lumen_macros::Node)]
44#[node(kind = "levels", name = "Levels", category = "processing")]
45pub struct Levels {
46 pub id: NodeId,
47 #[params]
48 pub params: LevelsParamsDelegate,
49
50 #[input()]
51 pub source: PortRef,
52}
53
54impl Default for Levels {
55 fn default() -> Self {
56 Self {
57 id: NodeId::new(0),
58 params: LevelsParamsDelegate::default(),
59 source: PortRef::empty(),
60 }
61 }
62}
63
64#[derive(Debug, Clone)]
65struct CompiledLevels {
66 node_id: NodeId,
67 params: LevelsParamsDelegate,
68 buffer: lumen_gpu::BufferId,
69}
70
71impl GpuCompiledNode for CompiledLevels {
72 fn node_id(&self) -> NodeId {
73 self.node_id
74 }
75
76 fn bind(&self, ctx: &FrameBindContext<'_>, bound: &mut BoundFrame) -> crate::Result<()> {
77 let params = self.params.eval(&NodeParamEvalContext {
78 node_id: self.node_id,
79 expr: &ctx.expr_context(self.node_id, "params"),
80 })?;
81 let gpu_params = compiler::LevelsParams {
82 black_point: params.black_point as f32,
83 white_point: params.white_point as f32,
84 gamma: params.gamma as f32,
85 output_black: params.output_black as f32,
86 output_white: params.output_white as f32,
87 _pad: [0.0; 3],
88 };
89 bound.write_buffer(self.buffer, 0, bytemuck::bytes_of(&gpu_params));
90 Ok(())
91 }
92}
93
94impl GpuCompileNode for Levels {
95 fn compile_gpu(
96 &self,
97 ctx: &mut crate::gpu::CompileContext<'_>,
98 port: &PortRef,
99 ) -> crate::Result<CompiledOutput> {
100 let (source, texture, params) = ctx.compile_unary_filter(
101 self.id,
102 &self.source,
103 port,
104 "levels",
105 SHADER,
106 std::mem::size_of::<compiler::LevelsParams>() as u64,
107 )?;
108 ctx.register_compiled_node(CompiledLevels {
109 node_id: self.id,
110 params: self.params.clone(),
111 buffer: params,
112 });
113 Ok(CompiledOutput::Raster(RasterHandle {
114 texture,
115 domain: source.domain,
116 metadata: source.metadata,
117 }))
118 }
119}