valora 0.2.8

A brush for generative fine art.
Documentation
//! Path rasterization.

use crate::{gpu::GpuVertex, Result, P2};
use lyon_path::Builder;
use lyon_tessellation::{
    BuffersBuilder, FillAttributes, FillOptions, FillTessellator, StrokeAttributes, StrokeOptions,
    StrokeTessellator, VertexBuffers,
};
use palette::LinSrgba;

/// The method by which the rasterizer will rasterize the vector path.
#[derive(Debug, Clone, Copy)]
pub enum Method {
    /// In fill method, the rasterizer will treat all the area inside the path as part of the
    /// raster area. In this method, paths are automatically closed by assuming an edge from the
    /// last to the first vertex.
    Fill,
    /// In stroke method, the rasterizer will treat the area immediately adjacent the path within
    /// the given width as part of the rastered area. In this method, paths are left open
    /// and no edge between the last and first vertex is assumed.
    Stroke(f32),
}

pub fn raster_path(
    builder: Builder,
    method: Method,
    color: LinSrgba,
) -> Result<(Vec<GpuVertex>, Vec<u32>)> {
    match method {
        Method::Fill => {
            let ctor = |v: P2, _: FillAttributes| -> P2 { v };
            let mut buffers: VertexBuffers<P2, u32> = VertexBuffers::new();
            let mut buffers_builder = BuffersBuilder::new(&mut buffers, ctor);

            let mut tessellator = FillTessellator::new();
            let result = tessellator.tessellate_path(
                &builder.build(),
                &FillOptions::default().with_tolerance(0.05),
                &mut buffers_builder,
            );
            match result {
                Ok(_) => {}
                Err(e) => panic!("Tessellation failed: {:?}", e),
            }

            Ok((
                buffers
                    .vertices
                    .into_iter()
                    .map(|v| GpuVertex {
                        vpos: [v.x, v.y],
                        vcol: [
                            color.color.red,
                            color.color.green,
                            color.color.blue,
                            color.alpha,
                        ],
                    })
                    .collect(),
                buffers.indices,
            ))
        }
        Method::Stroke(width) => {
            let ctor = |v: P2, _: StrokeAttributes| -> P2 { v };
            let mut buffers: VertexBuffers<P2, u32> = VertexBuffers::new();
            let mut buffers_builder = BuffersBuilder::new(&mut buffers, ctor);

            let mut tessellator = StrokeTessellator::new();
            tessellator
                .tessellate_path(
                    &builder.build(),
                    &StrokeOptions::default()
                        .with_line_width(width)
                        .with_tolerance(0.05),
                    &mut buffers_builder,
                )
                .expect("TODO: wrap error");

            Ok((
                buffers
                    .vertices
                    .into_iter()
                    .map(|v| GpuVertex {
                        vpos: [v.x, v.y],
                        vcol: [
                            color.color.red,
                            color.color.green,
                            color.color.blue,
                            color.alpha,
                        ],
                    })
                    .collect(),
                buffers.indices,
            ))
        }
    }
}