[−][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 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
andBasicVertexConstructor
, used byBuffersBuilder
in order to generate any vertex type. In the first example below, a structWithColor
implements theBasicVertexConstructor
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 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 |
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 |
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 |
MaxIndex | Provides the maximum value of an index. |
StrokeGeometryBuilder | A Geometry builder to interface with the |
StrokeVertexConstructor | A trait specifying how to create vertex values. |
Functions
simple_builder | Creates a |
vertex_builder | Creates a |
Type Definitions
SimpleBuffersBuilder | A |