Module lyon_tessellation::geometry_builder
source · Expand description
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 aVertexBuffers
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
andBuffersBuilder
in order to generate any vertex type. In the first example below, a structWithColor
implements theFillVertexConstructor
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 thePositions
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 FillVertexConstructor
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::{FillVertexConstructor, VertexBuffers, BuffersBuilder, FillOptions, FillTessellator, FillVertex};
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 FillVertexConstructor<MyVertex> for WithColor {
fn new_vertex(&mut self, vertex: FillVertex) -> MyVertex {
MyVertex {
position: vertex.position().to_array(),
color: self.0,
}
}
}
fn main() {
let mut output: VertexBuffers<MyVertex, u16> = VertexBuffers::new();
let mut tessellator = FillTessellator::new();
// Tessellate a red and a green circle.
tessellator.tessellate_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])
),
);
tessellator.tessellate_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::{StrokeTessellator, GeometryBuilder, StrokeGeometryBuilder, StrokeOptions, Count, GeometryBuilderError, StrokeVertex, VertexId};
use tess::math::{Point, point};
use tess::path::polygon::Polygon;
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, vertex: StrokeVertex) -> Result<VertexId, GeometryBuilderError> {
println!("vertex {:?}", 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();
let mut tessellator = StrokeTessellator::new();
tessellator.tessellate_polygon(
Polygon {
points: &[point(0.0, 0.0), point(10.0, 0.0), point(5.0, 5.0)],
closed: true,
},
&StrokeOptions::default(),
&mut output,
);
}
Structs
- A temporary view on a
VertexBuffers
object which facilitate the population of vertex and index data. - Number of vertices and indices added during the tessellation.
- A geometry builder that does not output any geometry.
- A simple vertex constructor that just takes the position.
- Structure that holds the vertex and index data.
Enums
- An error that can happen while generating geometry.
Traits
- A Geometry builder to interface with the
FillTessellator
. - A trait specifying how to create vertex values.
- An interface separating tessellators and other geometry generation algorithms from the actual vertex construction.
- Provides the maximum value of an index.
- A Geometry builder to interface with the
StrokeTessellator
. - A trait specifying how to create vertex values.
Functions
- Creates a
SimpleBuffersBuilder
.
Type Aliases
- A
BuffersBuilder
that takes the actual vertex type as input.