lumen_engine/node/processing/
exposure.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!("exposure.wgsl");
9
10#[derive(Debug, Clone, lumen_macros::Node)]
12#[node(kind = "exposure", name = "Exposure", category = "processing")]
13pub struct Exposure {
14 pub id: NodeId,
15 #[property(kind = "float", step = 0.01)]
17 pub exposure: NodeProperty,
18 #[property(kind = "float", min = 0, step = 0.01)]
20 pub contrast: NodeProperty,
21 #[property(kind = "float", step = 0.01)]
23 pub offset: NodeProperty,
24 #[input()]
25 pub source: PortRef,
26}
27
28impl Default for Exposure {
29 fn default() -> Self {
30 Self {
31 id: NodeId::new(0),
32 exposure: NodeProperty::Float(0.0),
33 contrast: NodeProperty::Float(1.0),
34 offset: NodeProperty::Float(0.0),
35 source: PortRef::empty(),
36 }
37 }
38}
39
40impl GpuCompileNode for Exposure {
41 fn compile_gpu(
42 &self,
43 ctx: &mut crate::gpu::CompileContext<'_>,
44 port: &PortRef,
45 ) -> crate::Result<CompiledOutput> {
46 let (source, texture, params) = ctx.compile_unary_filter(
47 self.id,
48 &self.source,
49 port,
50 "exposure",
51 SHADER,
52 std::mem::size_of::<compiler::ExposureParams>() as u64,
53 )?;
54 ctx.push_frame_binding(FrameBinding::Exposure {
55 node_id: self.id,
56 exposure: self.exposure.clone(),
57 contrast: self.contrast.clone(),
58 offset: self.offset.clone(),
59 buffer: params,
60 });
61 Ok(CompiledOutput::Raster(RasterHandle {
62 texture,
63 domain: source.domain,
64 metadata: source.metadata,
65 }))
66 }
67}
68
69impl GpuFrameBindNode for Exposure {
70 fn bind_gpu_frame(
71 &self,
72 ctx: &FrameBindContext<'_>,
73 binding: &FrameBinding,
74 bound: &mut BoundFrame,
75 ) -> crate::Result<()> {
76 let FrameBinding::Exposure {
77 node_id,
78 exposure,
79 contrast,
80 offset,
81 buffer,
82 } = binding
83 else {
84 return Ok(());
85 };
86 let params = compiler::ExposureParams {
87 exposure: exposure.resolve_float(
88 *node_id,
89 "exposure",
90 &ctx.expr_context(*node_id, "exposure"),
91 )? as f32,
92 contrast: contrast.resolve_float(
93 *node_id,
94 "contrast",
95 &ctx.expr_context(*node_id, "contrast"),
96 )? as f32,
97 offset: offset.resolve_float(
98 *node_id,
99 "offset",
100 &ctx.expr_context(*node_id, "offset"),
101 )? as f32,
102 _pad: 0.0,
103 };
104 bound.write_buffer(*buffer, 0, bytemuck::bytes_of(¶ms));
105 Ok(())
106 }
107}