easygpu_lyon/
builder.rs

1use std::sync::Arc;
2
3use easygpu::color::Rgba;
4use easygpu::renderer::Renderer;
5use lyon_tessellation::math::Point;
6use lyon_tessellation::path::Path;
7use lyon_tessellation::{
8    FillOptions, FillTessellator, GeometryBuilderError, StrokeOptions, StrokeTessellator,
9    TessellationError, VertexId,
10};
11
12use crate::shape::{Shape, Vertex};
13
14mod lyon_builders;
15
16#[derive(Default, Debug)]
17/// Builds a shape using lyon for tesselation
18pub struct ShapeBuilder {
19    zdepth: f32,
20    vertices: Vec<Vertex>,
21    indicies: Vec<u16>,
22
23    /// This RGBA color is used when tesselating a path with no color data
24    /// (Attributes in lyon terminology)
25    pub default_color: [f32; 4],
26}
27
28impl ShapeBuilder {
29    /// Create a new ShapeBuilder with a given ZDepth
30    ///
31    /// # Arguments
32    ///
33    /// * `zdepth` - The z depth for shapes in this builder to have
34    pub fn new(zdepth: f32, default_color: [f32; 4]) -> Self {
35        Self {
36            zdepth,
37            default_color,
38            ..Default::default()
39        }
40    }
41
42    /// Prepare and load this builder into the renderer.
43    ///
44    /// This does not consume the builder, because wgpu copies the buffer rather
45    /// than taking ownerhip.
46    pub fn prepare(&self, renderer: &Renderer) -> Shape {
47        let verticies = renderer.device.create_buffer(&self.vertices);
48        let indicies = renderer.device.create_index(&self.indicies);
49
50        Shape {
51            index_count: self.indicies.len() as u32,
52            vertices: Arc::new(verticies),
53            indices: Arc::new(indicies),
54        }
55    }
56
57    /// Fill an arbitrary path from `lyon::path`
58    pub fn fill(&mut self, path: &Path, options: &FillOptions) -> Result<(), TessellationError> {
59        let mut tesselator = FillTessellator::new();
60        tesselator.tessellate_with_ids(path.id_iter(), path, Some(path), options, self)?;
61        Ok(())
62    }
63
64    /// Stroke an arbitrary path from `lyon::path`
65    pub fn stroke(
66        &mut self,
67        path: &Path,
68        options: &StrokeOptions,
69    ) -> Result<(), TessellationError> {
70        let mut tesselator = StrokeTessellator::new();
71        tesselator.tessellate_with_ids(path.id_iter(), path, Some(path), options, self)?;
72        Ok(())
73    }
74
75    fn new_vertex(&mut self, point: Point, attributes: &[f32]) -> Vertex {
76        let attributes = if attributes.is_empty() {
77            &self.default_color
78        } else {
79            attributes
80        };
81
82        assert!(attributes.len() == 4, "Attributes should be RGBA");
83
84        Vertex {
85            color: Rgba {
86                r: attributes[0],
87                g: attributes[1],
88                b: attributes[2],
89                a: attributes[3],
90            }
91            .into(),
92            position: [point.x, point.y, self.zdepth],
93        }
94    }
95
96    fn add_vertex(
97        &mut self,
98        point: Point,
99        attributes: &[f32],
100    ) -> Result<VertexId, GeometryBuilderError> {
101        let vertex = self.new_vertex(point, attributes);
102        let new_id = VertexId(self.vertices.len() as u32);
103        self.vertices.push(vertex);
104        if self.vertices.len() > u16::MAX as usize {
105            return Err(GeometryBuilderError::TooManyVertices);
106        }
107
108        Ok(new_id)
109    }
110}