1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
use super::super::PMesh;
use super::PBuilder;
use crate::IndexType;
use lyon::math::Point;
use lyon::tessellation::geometry_builder::{MaxIndex, Positions};
pub use lyon::tessellation::StrokeBuilder;
use lyon::tessellation::{
    BuffersBuilder, StrokeOptions, StrokeTessellator, VertexBuffers, VertexId,
};
use std::ops::Add;

// TODO: allow other index sizes!

/// This structure wraps a `lyon::tesselation::StrokeTessellator` and adds functionality to apply transformations to the path being built.
pub struct PStroke<T>
where
    T: Add + IndexType + From<VertexId> + MaxIndex,
{
    tessellator: StrokeTessellator,
    options: StrokeOptions,
    geometry: VertexBuffers<Point, T>,
}

impl<T> PStroke<T>
where
    T: Add + IndexType + From<VertexId> + MaxIndex,
{
    /// Creates a new stroke tessellator with the given tolerance and width.
    pub fn new(width: f32, tol: f32) -> Self {
        // Will contain the result of the tessellation.
        let geometry: VertexBuffers<Point, T> = VertexBuffers::new();
        let tessellator = StrokeTessellator::new();
        let options = StrokeOptions::tolerance(tol).with_line_width(width);

        PStroke {
            tessellator,
            options,
            geometry,
        }
    }

    /// Draws the path using the given closure.
    pub fn draw<F>(&mut self, draw_commands: F) -> &mut Self
    where
        F: FnOnce(&mut PBuilder<StrokeBuilder>),
    {
        // TODO: Improve performance: Can I use the BuffersBuilder to directly write to the mesh?
        let geometry_builder = &mut BuffersBuilder::new(&mut self.geometry, Positions);
        let builder = self.tessellator.builder(&self.options, geometry_builder);
        let mut my_builder = PBuilder::new(builder);
        draw_commands(&mut my_builder);
        my_builder.build().unwrap();
        self
    }

    /// Builds a PMesh object, consuming the tessellator.
    pub fn build(self) -> PMesh<T> {
        PMesh::import_geometry(&self.geometry, false)
    }
}

impl<T> PMesh<T>
where
    T: Add + IndexType + From<VertexId> + MaxIndex,
{
    /// Fills the path built in the closure and appends it to the mesh.
    pub fn stroke<F>(&mut self, width: f32, tol: f32, draw_commands: F) -> &mut PMesh<T>
    where
        F: FnOnce(&mut PBuilder<StrokeBuilder>),
    {
        let mut tessellator = PStroke::<T>::new(width, tol);
        tessellator.draw(draw_commands);
        self.extend(&tessellator.build());
        self
    }
}