[][src]Module lyon_tessellation::geometry_builder

Tools to help with generating vertex and index buffers.

Overview

While it would be possible for the tessellation algorithms to manually generate vertex and index buffers with a certain layout, it would mean that most code using the tessellators have to copy and convert all generated vertices in order to have their own vertex layout, or de-interleaved vertex formats, which is a very common use-case.

In order to flexibly and efficiently build geometry of various flavors, this module contains a number of builder interfaces that centered around the idea of building vertex and index buffers without having to know about the final vertex and index types.

See:

The traits above are what the tessellators interface with. It is very common to push vertices and indices into a pair of vectors, so to facilitate this pattern this module also provides:

  • The struct VertexBuffers is a simple pair of vectors of indices and vertices (generic parameters).
  • The struct BuffersBuilder which writes into a VertexBuffers and implements the various gemoetry builder traits. It takes care of filling the buffers while producing vertices is delegated to a vertex constructor.
  • The traits FillVertexConstructor, StrokeVertexConstructor and BasicVertexConstructor, used by BuffersBuilder in order to generate any vertex type. In the first example below, a struct WithColor implements the BasicVertexConstructor trait in order to create vertices composed of a 2d position and a color value from an input 2d position. This separates the construction of vertex values from the assembly of the vertex buffers. Another, simpler example of vertex constructor is the Positions constructor which just returns the vertex position untransformed.

Geometry builders are a practical way to add one last step to the tessellation pipeline, such as applying a transform or clipping the geometry.

While this is module designed to facilitate the generation of vertex buffers and index buffers, nothing prevents a given GeometryBuilder implementation to only generate a vertex buffer without indices, or write into a completely different format. These builder traits are at the end of the tessellation pipelines and are meant for users of this crate to be able to adapt the output of the tessellators to their own needs.

Do I need to implement geometry builders or vertex constructors?

If you only generate a vertex buffer and an index buffer (as a pair of standard Vec), then the simplest option is to work with custom vertex constructors and use VertexBuffers and BuffersBuilder.

For more specific or elaborate use cases where control over where the vertices as written is needed such as building de-interleaved vertex buffers or writing directly into a mapped GPU buffer, implementing custom geometry builders is the right thing to do.

Which of the vertex constructor or geometry builder traits to implement (fill/stroke/basic variants), depends on which tessellators the builder or constructor will interface with.

Examples

Generating custom vertices

The example below implements the BasicVertexConstructor trait in order to use a custom vertex type MyVertex (containing position and color), storing the tessellation in a VertexBuffers<MyVertex, u16>, and tessellates two shapes with different colors.

extern crate lyon_tessellation as tess;
use tess::{BasicVertexConstructor, VertexBuffers, BuffersBuilder, FillOptions};
use tess::basic_shapes::fill_circle;
use tess::math::{Point, point};

// Our custom vertex.
#[derive(Copy, Clone, Debug)]
pub struct MyVertex {
  position: [f32; 2],
  color: [f32; 4],
}

// The vertex constructor. This is the object that will be used to create the custom
// verticex from the information provided by the tessellators.
struct WithColor([f32; 4]);

impl BasicVertexConstructor<MyVertex> for WithColor {
    fn new_vertex(&mut self, position: Point) -> MyVertex {
        MyVertex {
            position: [position.x, position.y],
            color: self.0,
        }
    }
}

fn main() {
    let mut output: VertexBuffers<MyVertex, u16> = VertexBuffers::new();
    // Tessellate a red and a green circle.
    fill_circle(
        point(0.0, 0.0),
        10.0,
        &FillOptions::tolerance(0.05),
        &mut BuffersBuilder::new(
            &mut output,
            WithColor([1.0, 0.0, 0.0, 1.0])
        ),
    );
    fill_circle(
        point(10.0, 0.0),
        5.0,
        &FillOptions::tolerance(0.05),
        &mut BuffersBuilder::new(
            &mut output,
            WithColor([0.0, 1.0, 0.0, 1.0])
        ),
    );

    println!(" -- {} vertices, {} indices", output.vertices.len(), output.indices.len());
}

Generating a completely custom output

Using VertexBuffers<T> is convenient and probably fits a lot of use cases, but what if we do not want to write the geometry in a pair of vectors? Perhaps we want to write the geometry in a different data structure or directly into gpu-accessible buffers mapped on the CPU?

extern crate lyon_tessellation as tess;
use tess::{GeometryBuilder, StrokeGeometryBuilder, StrokeOptions, Count, GeometryBuilderError, StrokeAttributes, VertexId};
use tess::basic_shapes::stroke_polyline;
use tess::math::{Point, point};
use std::fmt::Debug;
use std::u32;

// A geometry builder that writes the result of the tessellation to stdout instead
// of filling vertex and index buffers.
pub struct ToStdOut {
    vertices: u32,
    indices: u32,
}

impl ToStdOut {
     pub fn new() -> Self { ToStdOut { vertices: 0, indices: 0 } }
}

impl GeometryBuilder for ToStdOut {
    fn begin_geometry(&mut self) {
        // Reset the vertex in index counters.
        self.vertices = 0;
        self.indices = 0;
        println!(" -- begin geometry");
    }

    fn end_geometry(&mut self) -> Count {
        println!(" -- end geometry, {} vertices, {} indices", self.vertices, self.indices);
        Count {
            vertices: self.vertices,
            indices: self.indices,
        }
    }

    fn add_triangle(&mut self, a: VertexId, b: VertexId, c: VertexId) {
        println!("triangle ({}, {}, {})", a.offset(), b.offset(), c.offset());
        self.indices += 3;
    }

    fn abort_geometry(&mut self) {
        println!(" -- oops!");
    }
}

impl StrokeGeometryBuilder for ToStdOut {
    fn add_stroke_vertex(&mut self, position: Point, _: StrokeAttributes) -> Result<VertexId, GeometryBuilderError> {
        println!("vertex {:?}", position);
        if self.vertices >= u32::MAX {
            return Err(GeometryBuilderError::TooManyVertices);
        }
        self.vertices += 1;
        Ok(VertexId(self.vertices as u32 - 1))
    }
}

fn main() {
    let mut output = ToStdOut::new();
    stroke_polyline(
        [point(0.0, 0.0), point(10.0, 0.0), point(5.0, 5.0)].iter().cloned(),
        true,
        &StrokeOptions::default(),
        &mut output,
    );
}

Writing a tessellator

The example below is the implementation of basic_shapes::fill_rectangle.

use lyon_tessellation::geometry_builder::*;
use lyon_tessellation::{FillAttributes, TessellationResult};
use lyon_tessellation::math::{Rect, vector, point};

// A tessellator that generates an axis-aligned quad.
// Returns a structure containing the number of vertices and number of indices allocated
// during the execution of this method.
pub fn fill_rectangle<Output>(rect: &Rect, output: &mut Output) -> TessellationResult
where
    Output: BasicGeometryBuilder
{
    output.begin_geometry();
    // Create the vertices...
    let min = rect.min();
    let max = rect.max();
    let a = output.add_vertex(min)?;
    let b = output.add_vertex(point(max.x, min.y))?;
    let c = output.add_vertex(max)?;
    let d = output.add_vertex(point(min.x, max.y))?;
    // ...and create triangle form these points. a, b, c, and d are relative offsets in the
    // vertex buffer.
    output.add_triangle(a, b, c);
    output.add_triangle(a, c, d);

    Ok(output.end_geometry())
}

Structs

BuffersBuilder

A temporary view on a VertexBuffers object which facilitate the population of vertex and index data.

Count

Number of vertices and indices added during the tessellation.

NoOutput

A geometry builder that does not output any geometry.

Positions

A simple vertex constructor that just takes the position.

VertexBuffers

Structure that holds the vertex and index data.

Enums

GeometryBuilderError

An error that can happen while generating geometry.

Traits

BasicGeometryBuilder

A Geometry builder to interface with some of the basic tessellators.

BasicVertexConstructor

A trait specifying how to create vertex values.

FillGeometryBuilder

A Geometry builder to interface with the FillTessellator.

FillVertexConstructor

A trait specifying how to create vertex values.

GeometryBuilder

An interface separating tessellators and other geometry generation algorithms from the actual vertex construction.

GeometryReceiver

An interface with similar goals to GeometryBuilder for algorithms that pre-build the vertex and index buffers.

MaxIndex

Provides the maximum value of an index.

StrokeGeometryBuilder

A Geometry builder to interface with the StrokeTessellator.

StrokeVertexConstructor

A trait specifying how to create vertex values.

Functions

simple_builder

Creates a SimpleBuffersBuilder.

vertex_builder

Creates a BuffersBuilder.

Type Definitions

SimpleBuffersBuilder

A BuffersBuilder that takes the actual vertex type as input.