lumen_engine/node/vector/
shape.rs1use super::paint::Paint;
2use crate::gpu::{BoundFrame, CompiledOutput, FrameBindContext, GpuCompileNode, GpuCompiledNode};
3use crate::node::{NodeId, NodeParamEvalContext, NodeParams, PortRef};
4
5#[derive(
6 Debug, Clone, Copy, PartialEq, Eq, Default, lumen_macros::NodeEnum, lumen_macros::Delegate,
7)]
8#[repr(i64)]
9#[delegate(kind = "enum")]
10pub enum ShapeGeometryKind {
11 #[default]
12 Rectangle = 0,
13 Ellipse = 1,
14 Polygon = 2,
15}
16
17#[derive(Debug, Clone, lumen_macros::Delegate)]
19pub struct ShapeParams {
20 #[meta(kind = "enum", enum_type = ShapeGeometryKind)]
22 pub geometry_kind: ShapeGeometryKind,
23 #[meta(min = 1, step = 1)]
25 pub width: i64,
26 #[meta(min = 1, step = 1)]
28 pub height: i64,
29 #[meta(min = 0, step = 1)]
31 pub border_radius: f64,
32 #[meta(
34 name = "Polygon points",
35 format = "point_list",
36 multiline,
37 recommended_rows = 3
38 )]
39 pub polygon_points: String,
40 #[meta()]
42 pub position: (f64, f64),
43 #[meta()]
45 pub fill_enabled: bool,
46 #[meta()]
48 pub fill_paint: Paint,
49 #[meta()]
51 pub stroke_enabled: bool,
52 #[meta()]
54 pub stroke_paint: Paint,
55 #[meta(min = 0, step = 0.5)]
57 pub stroke_width: f64,
58}
59
60impl Default for ShapeParams {
61 fn default() -> Self {
62 Self {
63 geometry_kind: ShapeGeometryKind::Rectangle,
64 width: 1,
65 height: 1,
66 border_radius: 0.0,
67 polygon_points: String::new(),
68 position: (0.0, 0.0),
69 fill_enabled: true,
70 fill_paint: Paint::solid([255, 255, 255, 255]),
71 stroke_enabled: false,
72 stroke_paint: Paint::solid([0, 0, 0, 255]),
73 stroke_width: 1.0,
74 }
75 }
76}
77
78#[derive(Debug, Clone, lumen_macros::Node)]
80#[node(kind = "shape", name = "Shape", category = "vector")]
81pub struct Shape {
82 pub id: NodeId,
83 #[params]
84 pub params: ShapeParamsDelegate,
85}
86
87impl Default for Shape {
88 fn default() -> Self {
89 Self {
90 id: NodeId::new(0),
91 params: ShapeParamsDelegate::default(),
92 }
93 }
94}
95
96impl GpuCompileNode for Shape {
97 fn compile_gpu(
98 &self,
99 ctx: &mut crate::gpu::CompileContext<'_>,
100 port: &PortRef,
101 ) -> crate::Result<CompiledOutput> {
102 crate::node::vector::renderer::VectorRenderer::new(ctx).compile_shape(self, port)
103 }
104}
105
106#[derive(Debug, Clone)]
107pub(crate) struct CompiledShape {
108 pub(crate) node_id: NodeId,
109 pub(crate) params: ShapeParamsDelegate,
110 pub(crate) buffer: lumen_gpu::BufferId,
111}
112
113impl GpuCompiledNode for CompiledShape {
114 fn node_id(&self) -> NodeId {
115 self.node_id
116 }
117
118 fn bind(&self, ctx: &FrameBindContext<'_>, bound: &mut BoundFrame) -> crate::Result<()> {
119 let evaluated = self.params.eval(&NodeParamEvalContext {
120 node_id: self.node_id,
121 expr: &ctx.expr_context(self.node_id, "params"),
122 })?;
123 let (x, y) = evaluated.position;
124 let mut flags = 0;
125 if evaluated.fill_enabled {
126 flags |= 1;
127 }
128 if evaluated.stroke_enabled {
129 flags |= 2;
130 }
131 let params = super::renderer::ShapeParams {
132 fill_paint: evaluated.fill_paint.to_gpu([255, 255, 255, 255]),
133 stroke_paint: evaluated.stroke_paint.to_gpu([0, 0, 0, 255]),
134 position: [x as f32, y as f32],
135 size: [
136 evaluated.width.max(1) as f32,
137 evaluated.height.max(1) as f32,
138 ],
139 border_radius: evaluated.border_radius as f32,
140 stroke_width: evaluated.stroke_width as f32,
141 geometry_kind: evaluated.geometry_kind as u32,
142 flags,
143 };
144 bound.write_buffer(self.buffer, 0, bytemuck::bytes_of(¶ms));
145 Ok(())
146 }
147}