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