lumen_engine/node/processing/
transform.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!("transform.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 TransformSampling {
16 Nearest = 0,
17 #[default]
18 Linear = 1,
19}
20
21#[derive(Debug, Clone, lumen_macros::Delegate)]
23pub struct TransformParams {
24 #[meta(name = "Scale X", step = 0.1)]
26 pub scale_x: f64,
27 #[meta(name = "Scale Y", step = 0.1)]
29 pub scale_y: f64,
30 #[meta(name = "Translate X", step = 1)]
32 pub translate_x: f64,
33 #[meta(name = "Translate Y", step = 1)]
35 pub translate_y: f64,
36 #[meta(name = "Rotate", step = 1)]
38 pub rotate: f64,
39 #[meta(name = "Pivot X", step = 1)]
41 pub pivot_x: f64,
42 #[meta(name = "Pivot Y", step = 1)]
44 pub pivot_y: f64,
45 #[meta(kind = "enum", enum_type = TransformSampling)]
47 pub sampling: TransformSampling,
48}
49
50impl Default for TransformParams {
51 fn default() -> Self {
52 Self {
53 scale_x: 1.0,
54 scale_y: 1.0,
55 translate_x: 0.0,
56 translate_y: 0.0,
57 rotate: 0.0,
58 pivot_x: 0.0,
59 pivot_y: 0.0,
60 sampling: TransformSampling::Linear,
61 }
62 }
63}
64
65#[derive(Debug, Clone, lumen_macros::Node)]
67#[node(kind = "transform", name = "Transform", category = "processing")]
68pub struct Transform {
69 pub id: NodeId,
70 #[params]
71 pub params: TransformParamsDelegate,
72
73 #[input()]
74 pub source: PortRef,
75}
76
77impl Default for Transform {
78 fn default() -> Self {
79 Self {
80 id: NodeId::new(0),
81 params: TransformParamsDelegate::default(),
82 source: PortRef::empty(),
83 }
84 }
85}
86
87impl GpuCompileNode for Transform {
88 fn compile_gpu(
89 &self,
90 ctx: &mut crate::gpu::CompileContext<'_>,
91 port: &PortRef,
92 ) -> crate::Result<CompiledOutput> {
93 let (source, texture, params) = ctx.compile_unary_filter(
94 self.id,
95 &self.source,
96 port,
97 "transform",
98 SHADER,
99 std::mem::size_of::<compiler::TransformParams>() as u64,
100 )?;
101 ctx.register_compiled_node(CompiledTransform {
102 node_id: self.id,
103 params: self.params.clone(),
104 buffer: params,
105 });
106 Ok(CompiledOutput::Raster(RasterHandle {
107 texture,
108 domain: source.domain,
109 metadata: source.metadata,
110 }))
111 }
112}
113
114#[derive(Debug, Clone)]
115struct CompiledTransform {
116 node_id: NodeId,
117 params: TransformParamsDelegate,
118 buffer: lumen_gpu::BufferId,
119}
120
121impl GpuCompiledNode for CompiledTransform {
122 fn node_id(&self) -> NodeId {
123 self.node_id
124 }
125
126 fn bind(&self, ctx: &FrameBindContext<'_>, bound: &mut BoundFrame) -> crate::Result<()> {
127 let evaluated = self.params.eval(&NodeParamEvalContext {
128 node_id: self.node_id,
129 expr: &ctx.expr_context(self.node_id, "params"),
130 })?;
131 let params = compiler::TransformParams {
132 scale: [evaluated.scale_x as f32, evaluated.scale_y as f32],
133 translate: [evaluated.translate_x as f32, evaluated.translate_y as f32],
134 pivot: [evaluated.pivot_x as f32, evaluated.pivot_y as f32],
135 rotate_radians: (evaluated.rotate as f32).to_radians(),
136 sampling: evaluated.sampling as u32,
137 _pad: [0; 4],
138 };
139 bound.write_buffer(self.buffer, 0, bytemuck::bytes_of(¶ms));
140 Ok(())
141 }
142}