[][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 would need to copy and convert all generated vertices in order to have their own vertex layout, or even several vertex layouts, which is a very common use-case.

In order to provide flexibility with the generation of geometry, this module provides with the GeometryBuilder and its extension the BezierGeometryBuilder trait. The former exposes the methods to facilitate adding vertices and triangles. The latter adds a method to specifically handle quadratic bezier curves. Quadratic bézier curves have interesting properties that make them a lot easier to render than most types of curves and we want to have the option to handle them separately in the renderer.

See the Rendering curves section in the project's wiki for more details about the advantages of handling quadratic bézier curves separately in the tessellator and the renderer.

This modules provides with a basic implementation of these traits through the following types:

  • The struct VertexBuffers<T> is a simple pair of vectors of u32 indices and T (generic parameter) vertices.
  • The struct BuffersBuilder which implements BezierGeometryBuilder and writes into a VertexBuffers.
  • The trait VertexConstructor used by BuffersBuilder in order to generate any vertex type. In the example below, a struct WithColor implements the VertexConstructor 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 Identity constructor which just returns its input, untransformed. VertexConstructor<Input, Output> is implemented for all closures Fn(Input) -> Output.

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.

Examples

Generating custom vertices

The example below implements the VertexConstructor 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::{VertexConstructor, VertexBuffers, BuffersBuilder, FillVertex, FillOptions};
use tess::basic_shapes::fill_circle;
use tess::math::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 VertexConstructor<FillVertex, MyVertex> for WithColor {
    fn new_vertex(&mut self, vertex: FillVertex) -> MyVertex {
        // FillVertex also provides normals but we don't need it here.
        MyVertex {
            position: [
                vertex.position.x,
                vertex.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, StrokeOptions, Count};
use tess::geometry_builder::{VertexId, GeometryBuilderError};
use tess::basic_shapes::stroke_polyline;
use tess::math::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 } }
}

// This one takes any vertex type that implements Debug, so it will work with both
// FillVertex and StrokeVertex.
impl<Vertex: Debug> GeometryBuilder<Vertex> 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_vertex(&mut self, vertex: Vertex) -> Result<VertexId, GeometryBuilderError> {
        println!("vertex {:?}", vertex);
        if self.vertices >= u32::MAX {
            return Err(GeometryBuilderError::TooManyVertices);
        }
        self.vertices += 1;
        Ok(VertexId(self.vertices as u32 - 1))
    }

    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!");
    }
}

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::{FillVertex, TessellationResult};
use lyon_tessellation::math::{Rect, vector};

// 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: GeometryBuilder<FillVertex>
{
    output.begin_geometry();
    // Create the vertices...
    let a = output.add_vertex(
        FillVertex { position: rect.origin, normal: vector(-1.0, -1.0) }
    )?;
    let b = output.add_vertex(
        FillVertex { position: rect.top_right(), normal: vector(1.0, -1.0) }
    )?;
    let c = output.add_vertex(
        FillVertex { position: rect.bottom_right(), normal: vector(1.0, 1.0) }
    )?;
    let d = output.add_vertex(
        FillVertex { position: rect.bottom_left(), normal: vector(-1.0, 1.0) }
    )?;
    // ...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.

Identity

A dummy vertex constructor that just forwards its inputs.

NoOutput

A geometry builder that does not output any geometry.

VertexBuffers

Structure that holds the vertex and index data.

VertexId

A virtual vertex offset in a geometry.

Enums

GeometryBuilderError

An error that can happen while generating geometry.

Traits

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.

VertexConstructor

A trait specifying how to create vertex values.

Functions

simple_builder

Creates a SimpleBuffersBuilder.

vertex_builder

Creates a BuffersBuilder.

Type Definitions

Index
SimpleBuffersBuilder

A BuffersBuilder that takes the actual vertex type as input.