logo
  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>;
}