lumen_engine/node/processing/
channel_shuffle.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!("channel_shuffle.wgsl");
9
10#[derive(
11 Debug, Clone, Copy, PartialEq, Eq, Default, lumen_macros::NodeEnum, lumen_macros::Delegate,
12)]
13#[repr(i64)]
14#[delegate(kind = "enum")]
15pub enum ChannelSelector {
16 #[default]
17 Red = 0,
18 Green = 1,
19 Blue = 2,
20 Alpha = 3,
21 Zero = 4,
22 One = 5,
23}
24
25impl ChannelSelector {
26 fn as_spec(self) -> &'static str {
27 match self {
28 Self::Red => "red",
29 Self::Green => "green",
30 Self::Blue => "blue",
31 Self::Alpha => "alpha",
32 Self::Zero => "zero",
33 Self::One => "one",
34 }
35 }
36}
37
38#[derive(Debug, Clone, lumen_macros::Delegate)]
40pub struct ChannelShuffleParams {
41 #[meta(kind = "enum", enum_type = ChannelSelector)]
43 pub red: ChannelSelector,
44 #[meta(kind = "enum", enum_type = ChannelSelector)]
46 pub green: ChannelSelector,
47 #[meta(kind = "enum", enum_type = ChannelSelector)]
49 pub blue: ChannelSelector,
50 #[meta(kind = "enum", enum_type = ChannelSelector)]
52 pub alpha: ChannelSelector,
53}
54
55impl Default for ChannelShuffleParams {
56 fn default() -> Self {
57 Self {
58 red: ChannelSelector::Red,
59 green: ChannelSelector::Green,
60 blue: ChannelSelector::Blue,
61 alpha: ChannelSelector::Alpha,
62 }
63 }
64}
65
66#[derive(Debug, Clone, lumen_macros::Node)]
68#[node(
69 kind = "channel_shuffle",
70 name = "Channel Shuffle",
71 category = "processing"
72)]
73pub struct ChannelShuffle {
74 pub id: NodeId,
75 #[params]
76 pub params: ChannelShuffleParamsDelegate,
77
78 #[input()]
79 pub source: PortRef,
80}
81
82impl Default for ChannelShuffle {
83 fn default() -> Self {
84 Self {
85 id: NodeId::new(0),
86 params: ChannelShuffleParamsDelegate::default(),
87 source: PortRef::empty(),
88 }
89 }
90}
91
92#[derive(Debug, Clone)]
93struct CompiledChannelShuffle {
94 node_id: NodeId,
95 params: ChannelShuffleParamsDelegate,
96 buffer: lumen_gpu::BufferId,
97}
98
99impl GpuCompiledNode for CompiledChannelShuffle {
100 fn node_id(&self) -> NodeId {
101 self.node_id
102 }
103
104 fn bind(&self, ctx: &FrameBindContext<'_>, bound: &mut BoundFrame) -> crate::Result<()> {
105 let params = self.params.eval(&NodeParamEvalContext {
106 node_id: self.node_id,
107 expr: &ctx.expr_context(self.node_id, "params"),
108 })?;
109 let selectors = [
110 compiler::channel_selector(self.node_id, "red", params.red.as_spec())?,
111 compiler::channel_selector(self.node_id, "green", params.green.as_spec())?,
112 compiler::channel_selector(self.node_id, "blue", params.blue.as_spec())?,
113 compiler::channel_selector(self.node_id, "alpha", params.alpha.as_spec())?,
114 ];
115 let gpu_params = compiler::ChannelShuffleParams {
116 selector_indices: selectors.map(|selector| selector.index),
117 selector_values: selectors.map(|selector| selector.value),
118 };
119 bound.write_buffer(self.buffer, 0, bytemuck::bytes_of(&gpu_params));
120 Ok(())
121 }
122}
123
124impl GpuCompileNode for ChannelShuffle {
125 fn compile_gpu(
126 &self,
127 ctx: &mut crate::gpu::CompileContext<'_>,
128 port: &PortRef,
129 ) -> crate::Result<CompiledOutput> {
130 let (source, texture, params) = ctx.compile_unary_filter(
131 self.id,
132 &self.source,
133 port,
134 "channel-shuffle",
135 SHADER,
136 std::mem::size_of::<compiler::ChannelShuffleParams>() as u64,
137 )?;
138 ctx.register_compiled_node(CompiledChannelShuffle {
139 node_id: self.id,
140 params: self.params.clone(),
141 buffer: params,
142 });
143 Ok(CompiledOutput::Raster(RasterHandle {
144 texture,
145 domain: source.domain,
146 metadata: source.metadata,
147 }))
148 }
149}