1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
//! Tessellation backend interface.
//!
//! This interface defines the low-level backends must implement to be usable.
//!
//! Tessellations are the way to gather _vertices_ and other various kind of information to draw shapes in framebuffers.
//! They come with several concepts that are important to understand:
//!
//! - Memory layout: either [`Interleaved`] or [`Deinterleaved`].
//! - Vertices. Vertices are passed to tessellations in a different way depending on the memory layout. Basically, for
//! the [`Interleaved`] memory layout, a single slice of vertices is needed. With [`Deinterleaved`], data must be
//! provided via different slices (one for each attribute).
//! - Indices, which allow to index vertices, reducing the amount of data to send and prevent duplicates.
//! - Primitive modes which connect vertices in specific ways (lines, line strips, triangles, etc.).
//! - Instance data, which is vertex data associated with the tessellation but available only to specific instances.
//!
//! [`Interleaved`]: crate::tess::Interleaved
//! [`Deinterleaved`]: crate::tess::Deinterleaved
use std::ops::{Deref, DerefMut};
use crate::tess::{Mode, TessError, TessIndex, TessMapError, TessVertexData};
/// Tessellation support on the backend.
///
/// This trait is a bit complex at first glance because of the number of type variables.
///
/// - `V` is the type of vertex, and requires the [`TessVertexData`] trait to be implemented with `S`. More on this
/// below.
/// - `I` is the type of index, and requires the [`TessIndex`] trait to be implemented.
/// - `W` is the type of instance and also requires [`TessVertexData`]:
/// - `S` is the storage type and acts as a marker for backends.
///
/// `S` is an important type variable here, because it gives the [`Tess`] its memory storage layout. You can use any
/// type you want here but as a backend, you will want to implement [`Tess`] for `S` with the [`Interleaved`] and
/// [`Deinterleaved`] types. Those two types are the ones used in the API, so the backends are expected to implement
/// them.
///
/// You will want to have a look at [`TessVertexData`] and [`TessIndex`] to know how to make your vertex and index types
/// compatible with [`Tess`].
///
/// [`Interleaved`]: crate::tess::Interleaved
/// [`Deinterleaved`]: crate::tess::Deinterleaved
pub unsafe trait Tess<V, I, W, S>
where
V: TessVertexData<S>,
I: TessIndex,
W: TessVertexData<S>,
S: ?Sized,
{
/// Backend representation of the tessellation.
type TessRepr;
/// Build a tessellation from vertex, index, instance and mode data.
///
/// This method is used after a builder has enough information to build a [`Tess`]. The data is highly polymorphic so
/// you will have to provide the types for the data containers when implementing both [`TessVertexData`] and
/// [`TessIndex`]. By convention, the idea is that:
///
/// - If `S` is [`Interleaved`], you will want to take a single [`Vec`] for vertices and either a [`Vec`] or [`()`]
/// for indices and instance data.
/// - If `S` is [`Deinterleaved`], you will want to take a [`Vec`] of [`DeinterleavedData`] for vertices and instance
/// data (it doesn’t make any difference for indices, so stick to [`Vec`] and [`()`]). [`DeinterleavedData`]
/// contains its own [`Vec`], so you basically end up with a [`Vec`] of [`Vec`], allowing to provide separate
/// attributes for all the vertices in their own containers.
///
/// [`Interleaved`]: crate::tess::Interleaved
/// [`Deinterleaved`]: crate::tess::Deinterleaved
/// [`DeinterleavedData`]: crate::tess::DeinterleavedData
unsafe fn build(
&mut self,
vertex_data: Option<V::Data>,
index_data: Vec<I>,
instance_data: Option<W::Data>,
mode: Mode,
restart_index: Option<I>,
) -> Result<Self::TessRepr, TessError>;
/// Number of vertices available in the [`Tess`].
unsafe fn tess_vertices_nb(tess: &Self::TessRepr) -> usize;
/// Number of indices available in the [`Tess`].
unsafe fn tess_indices_nb(tess: &Self::TessRepr) -> usize;
/// Number of instance data available in the [`Tess`].
unsafe fn tess_instances_nb(tess: &Self::TessRepr) -> usize;
/// Render the tessellation, starting at `start_index`, rendering `vert_nb` vertices, instantiating `inst_nb` times.
///
/// If `inst_nb` is `0`, you should perform a render as if you were asking for `1`.
unsafe fn render(
tess: &Self::TessRepr,
start_index: usize,
vert_nb: usize,
inst_nb: usize,
) -> Result<(), TessError>;
}
/// Slice vertex data on CPU.
///
/// This trait must be implemented by the backend so that it’s possible to _slice_ the vertex data. The idea is that the
/// vertex storage is backend-dependent; the backend can decide to cache the data, or not, and we should assume the data
/// to live in a memory that is costly to access. For this reason, slicing the vertex data requires to get an object on
/// which one can use [`Deref`] (and possibly [`DerefMut`]). The [`VertexSlice::vertices`] and
/// [`VertexSlice::vertices_mut`] methods must get such objects. Implementations will typically map memory regions and
/// retain the mapped data until the [`VertexSlice::VertexSliceRepr`] and [`VertexSlice::VertexSliceMutRepr`] objects
/// are dropped (c.f. [`Drop`]).
pub unsafe trait VertexSlice<'a, V, I, W, S, T>: Tess<V, I, W, S>
where
V: TessVertexData<S>,
I: TessIndex,
W: TessVertexData<S>,
S: ?Sized,
{
/// Backend representation of an immutable vertex slice.
type VertexSliceRepr: 'a + Deref<Target = [T]>;
/// Backend representation of a mutable vertex slice.
type VertexSliceMutRepr: 'a + DerefMut<Target = [T]>;
/// Obtain an immutable vertex slice.
///
/// Even though this method returns an immutable slice, it has to mutably borrow the tessellation to prevent having
/// two immutable slices living at the same time. This is a limitation that some backends might need.
unsafe fn vertices(tess: &'a mut Self::TessRepr) -> Result<Self::VertexSliceRepr, TessMapError>;
/// Obtain a mutable vertex slice.
unsafe fn vertices_mut(
tess: &'a mut Self::TessRepr,
) -> Result<Self::VertexSliceMutRepr, TessMapError>;
}
/// Slice index data on CPU.
///
/// This trait must be implemented by the backend so that it’s possible to _slice_ the index data. The idea is that the
/// index storage is backend-dependent; the backend can decide to cache the data, or not, and we should assume the data
/// to live in a memory that is costly to access. For this reason, slicing the index data requires to get an object on
/// which one can use [`Deref`] (and possibly [`DerefMut`]). The [`IndexSlice::indices`] and
/// [`IndexSlice::indices_mut`] methods must get such objects. Implementations will typically map memory regions and
/// retain the mapped data until the [`IndexSlice::IndexSliceRepr`] and [`IndexSlice::IndexSliceMutRepr`] objects
/// are dropped (c.f. [`Drop`]).
pub unsafe trait IndexSlice<'a, V, I, W, S>: Tess<V, I, W, S>
where
V: TessVertexData<S>,
I: TessIndex,
W: TessVertexData<S>,
S: ?Sized,
{
/// Backend representation of an immutable index slice.
type IndexSliceRepr: 'a + Deref<Target = [I]>;
/// Backend representation of a mutable index slice.
type IndexSliceMutRepr: 'a + DerefMut<Target = [I]>;
/// Obtain an immutable index slice.
///
/// Even though this method returns an immutable slice, it has to mutably borrow the tessellation to prevent having
/// two immutable slices living at the same time. This is a limitation that some backends might need.
unsafe fn indices(tess: &'a mut Self::TessRepr) -> Result<Self::IndexSliceRepr, TessMapError>;
/// Obtain a mutable index slice.
unsafe fn indices_mut(
tess: &'a mut Self::TessRepr,
) -> Result<Self::IndexSliceMutRepr, TessMapError>;
}
/// Slice instance data on CPU.
///
/// This trait must be implemented by the backend so that it’s possible to _slice_ the instance data. The idea is that the
/// instance storage is backend-dependent; the backend can decide to cache the data, or not, and we should assume the data
/// to live in a memory that is costly to access. For this reason, slicing the instance data requires to get an object on
/// which one can use [`Deref`] (and possibly [`DerefMut`]). The [`InstanceSlice::instances`] and
/// [`InstanceSlice::instances_mut`] methods must get such objects. Implementations will typically map memory regions and
/// retain the mapped data until the [`InstanceSlice::InstanceSliceRepr`] and [`InstanceSlice::InstanceSliceMutRepr`] objects
/// are dropped (c.f. [`Drop`]).
pub unsafe trait InstanceSlice<'a, V, I, W, S, T>: Tess<V, I, W, S>
where
V: TessVertexData<S>,
I: TessIndex,
W: TessVertexData<S>,
S: ?Sized,
{
/// Backend representation of an immutable instance slice.
type InstanceSliceRepr: 'a + Deref<Target = [T]>;
/// Backend representation of a mutable instance slice.
type InstanceSliceMutRepr: 'a + DerefMut<Target = [T]>;
/// Obtain an immutable instance slice.
///
/// Even though this method returns an immutable slice, it has to mutably borrow the tessellation to prevent having
/// two immutable slices living at the same time. This is a limitation that some backends might need.
unsafe fn instances(
tess: &'a mut Self::TessRepr,
) -> Result<Self::InstanceSliceRepr, TessMapError>;
/// Obtain a mutable instance slice.
unsafe fn instances_mut(
tess: &'a mut Self::TessRepr,
) -> Result<Self::InstanceSliceMutRepr, TessMapError>;
}