luminance/
vertex.rs

1//! Vertex formats, associated types and functions.
2//!
3//! A vertex is a type representing a point. It’s common to find vertex positions, normals, colors
4//! or even texture coordinates. Even though you’re free to use whichever type you want, you’re
5//! limited to a range of types and dimensions. See [`VertexAttribType`] and [`VertexAttribDim`]
6//! for further details.
7//!
8//! [`VertexAttribDim`]: crate::vertex::VertexAttribDim
9//! [`VertexAttribType`]: crate::vertex::VertexAttribType
10
11use std::fmt::Debug;
12
13/// A type that can be used as a [`Vertex`] has to implement that trait – it must provide an
14/// associated [`VertexDesc`] value via a function call. This associated value gives enough
15/// information on the types being used as attributes to reify enough memory data to align and, size
16/// and type buffers correctly.
17///
18/// In theory, you should never have to implement that trait directly. Instead, feel free to use the
19/// [luminance-derive] [`Vertex`] proc-macro-derive instead.
20///
21/// > Note: implementing this trait is `unsafe`.
22pub unsafe trait Vertex: Copy {
23  /// The associated vertex format.
24  fn vertex_desc() -> VertexDesc;
25}
26
27unsafe impl Vertex for () {
28  fn vertex_desc() -> VertexDesc {
29    Vec::new()
30  }
31}
32
33/// TODO
34pub trait Deinterleave<T> {
35  /// Rank of the type in the original type.
36  const RANK: usize;
37}
38
39/// A [`VertexDesc`] is a list of [`VertexBufferDesc`]s.
40pub type VertexDesc = Vec<VertexBufferDesc>;
41
42/// A vertex attribute descriptor in a vertex buffer.
43///
44/// Such a description is used to state what vertex buffers are made of and how they should be
45/// aligned / etc.
46#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
47pub struct VertexBufferDesc {
48  /// Internal index of the attribute.
49  ///
50  /// That index is used as a mapping with vertex shaders to know how to fetch vertex attributes.
51  pub index: usize,
52  /// The name of the attribute.
53  ///
54  /// Such a name is used in vertex shaders to perform mapping.
55  pub name: &'static str,
56  /// Whether _vertex instancing_ should be used with that vertex attribute.
57  pub instancing: VertexInstancing,
58  /// Vertex attribute descriptor.
59  pub attrib_desc: VertexAttribDesc,
60}
61
62impl VertexBufferDesc {
63  /// Create a new [`VertexBufferDesc`].
64  pub fn new<S>(sem: S, instancing: VertexInstancing, attrib_desc: VertexAttribDesc) -> Self
65  where
66    S: Semantics,
67  {
68    let index = sem.index();
69    let name = sem.name();
70    VertexBufferDesc {
71      index,
72      name,
73      instancing,
74      attrib_desc,
75    }
76  }
77}
78
79/// Should vertex instancing be used for a vertex attribute?
80///
81/// Enabling this is done per attribute but if you enable it for a single attribute of a struct, it
82/// should be enabled for all others (interleaved vertex instancing is not supported).
83#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
84pub enum VertexInstancing {
85  /// Use vertex instancing.
86  On,
87  /// Disable vertex instancing.
88  Off,
89}
90
91/// Vertex attribute format.
92///
93/// Vertex attributes (such as positions, colors, texture UVs, normals, etc.) have all a specific
94/// format that must be passed to the GPU. This type gathers information about a single vertex
95/// attribute and is completly agnostic of the rest of the attributes used to form a vertex.
96///
97/// A type is associated with a single value of type [`VertexAttribDesc`] via the [`VertexAttrib`]
98/// trait. If such an implementor exists for a type, it means that this type can be used as a vertex
99/// attribute.
100#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
101pub struct VertexAttribDesc {
102  /// Type of the attribute. See [`VertexAttribType`] for further details.
103  pub ty: VertexAttribType,
104  /// Dimension of the attribute. It should be in 1–4. See [`VertexAttribDim`] for further details.
105  pub dim: VertexAttribDim,
106  /// Size in bytes that a single element of the attribute takes. That is, if your attribute has
107  /// a dimension set to 2, then the unit size should be the size of a single element (not two).
108  pub unit_size: usize,
109  /// Alignment of the attribute. The best advice is to respect what Rust does, so it’s highly
110  /// recommended to use `::std::mem::align_of` to let it does the job for you.
111  pub align: usize,
112}
113
114impl VertexAttribDesc {
115  /// Normalize a vertex attribute format’s type.
116  pub fn normalize(self) -> Self {
117    VertexAttribDesc {
118      ty: self.ty.normalize(),
119      ..self
120    }
121  }
122}
123
124/// Possible type of vertex attributes.
125#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
126pub enum VertexAttribType {
127  /// An integral type.
128  ///
129  /// Typically, `i32` is integral but not `u32`.
130  Integral(Normalized),
131  /// An unsigned integral type.
132  ///
133  /// Typically, `u32` is unsigned but not `i32`.
134  Unsigned(Normalized),
135  /// A floating point integral type.
136  Floating,
137  /// A boolean integral type.
138  Boolean,
139}
140
141impl VertexAttribType {
142  /// Normalize a vertex attribute type if it’s integral.
143  ///
144  /// Return the normalized integer vertex attribute type if non-normalized. Otherwise, return the
145  /// vertex attribute type directly.
146  pub fn normalize(self) -> Self {
147    match self {
148      VertexAttribType::Integral(Normalized::No) => VertexAttribType::Integral(Normalized::Yes),
149      VertexAttribType::Unsigned(Normalized::No) => VertexAttribType::Unsigned(Normalized::Yes),
150      _ => self,
151    }
152  }
153}
154
155/// Whether an integral vertex type should be normalized when fetched from a shader program.
156///
157/// The default implementation is not to normalize anything. You have to explicitly ask for
158/// normalized integers (that will, then, be accessed as floating vertex attributes).
159#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
160pub enum Normalized {
161  /// Normalize integral values and expose them as floating-point values.
162  Yes,
163  /// Do not perform any normalization and hence leave integral values as-is.
164  No,
165}
166
167/// Possible dimension of vertex attributes.
168#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
169pub enum VertexAttribDim {
170  /// 1D.
171  Dim1,
172  /// 2D.
173  Dim2,
174  /// 3D.
175  Dim3,
176  /// 4D.
177  Dim4,
178}
179
180/// Class of vertex attributes.
181///
182/// A vertex attribute type is always associated with a single constant of type [`VertexAttribDesc`],
183/// giving GPUs hints about how to treat them.
184pub unsafe trait VertexAttrib {
185  /// The vertex attribute descriptor.
186  const VERTEX_ATTRIB_DESC: VertexAttribDesc;
187}
188
189/// Vertex attribute semantics.
190///
191/// Vertex attribute semantics are a mean to make shaders and vertex buffers talk to each other
192/// correctly. This is important for several reasons:
193///
194///   - The memory layout of your vertex buffers might be very different from an ideal case or even
195///     the common case. Shaders don’t have any way to know where to pick vertex attributes from, so
196///     a mapping is needed.
197///   - Sometimes, a shader just need a few information from the vertex attributes. You then want to
198///     be able to authorize _“gaps”_ in the semantics so that shaders can be used for several
199///     varieties of vertex formats.
200///
201/// Vertex attribute semantics are any type that can implement this trait. The idea is that
202/// semantics must be unique. The vertex position should have an index that is never used anywhere
203/// else in the vertex buffer. Because of the second point above, it’s also highly recommended
204/// (even though valid not to) to stick to the same index for a given semantics when you have
205/// several tessellations – that allows better composition with shaders. Basically, the best advice
206/// to follow: define your semantics once, and keep to them.
207///
208/// > Note: feel free to use the [luminance-derive] crate to automatically derive this trait from
209/// > an `enum`.
210pub trait Semantics: Sized + Copy + Clone + Debug {
211  /// Retrieve the semantics index of this semantics.
212  fn index(&self) -> usize;
213  /// Get the name of this semantics.
214  fn name(&self) -> &'static str;
215  /// Get all available semantics.
216  fn semantics_set() -> Vec<SemanticsDesc>;
217}
218
219impl Semantics for () {
220  fn index(&self) -> usize {
221    0
222  }
223
224  fn name(&self) -> &'static str {
225    ""
226  }
227
228  fn semantics_set() -> Vec<SemanticsDesc> {
229    Vec::new()
230  }
231}
232
233/// Semantics description.
234#[derive(Clone, Debug, Eq, Hash, PartialEq)]
235pub struct SemanticsDesc {
236  /// Semantics index.
237  pub index: usize,
238  /// Name of the semantics (used in shaders).
239  pub name: String,
240}
241
242/// Class of types that have an associated value which type implements [`Semantics`], defining
243/// vertex legit attributes.
244///
245/// Vertex attribute types can be associated with only one semantics.
246pub trait HasSemantics {
247  /// Type of the semantics.
248  ///
249  /// See the [`Semantics`] trait for further information.
250  type Sem: Semantics;
251
252  /// The aforementioned vertex semantics for the attribute type.
253  const SEMANTICS: Self::Sem;
254}
255
256/// A local version of size_of that depends on the state of the std feature.
257#[inline(always)]
258const fn size_of<T>() -> usize {
259  #[cfg(feature = "std")]
260  {
261    ::std::mem::size_of::<T>()
262  }
263
264  #[cfg(not(feature = "std"))]
265  {
266    ::core::mem::size_of::<T>()
267  }
268}
269
270/// A local version of align_of that depends on the state of the std feature.
271#[inline(always)]
272const fn align_of<T>() -> usize {
273  #[cfg(feature = "std")]
274  {
275    ::std::mem::align_of::<T>()
276  }
277
278  #[cfg(not(feature = "std"))]
279  {
280    ::core::mem::align_of::<T>()
281  }
282}
283
284// Macro to quickly implement VertexAttrib for a given type.
285macro_rules! impl_vertex_attribute {
286  ($t:ty, $q:ty, $attr_ty:expr, $dim:expr) => {
287    unsafe impl VertexAttrib for $t {
288      const VERTEX_ATTRIB_DESC: VertexAttribDesc = VertexAttribDesc {
289        ty: $attr_ty,
290        dim: $dim,
291        unit_size: $crate::vertex::size_of::<$q>(),
292        align: $crate::vertex::align_of::<$q>(),
293      };
294    }
295  };
296
297  ($t:ty, $attr_ty:expr) => {
298    impl_vertex_attribute!($t, $t, $attr_ty, VertexAttribDim::Dim1);
299    impl_vertex_attribute!([$t; 1], $t, $attr_ty, VertexAttribDim::Dim1);
300    impl_vertex_attribute!([$t; 2], $t, $attr_ty, VertexAttribDim::Dim2);
301    impl_vertex_attribute!([$t; 3], $t, $attr_ty, VertexAttribDim::Dim3);
302    impl_vertex_attribute!([$t; 4], $t, $attr_ty, VertexAttribDim::Dim4);
303  };
304}
305
306impl_vertex_attribute!(i8, VertexAttribType::Integral(Normalized::No));
307impl_vertex_attribute!(i16, VertexAttribType::Integral(Normalized::No));
308impl_vertex_attribute!(i32, VertexAttribType::Integral(Normalized::No));
309impl_vertex_attribute!(u8, VertexAttribType::Unsigned(Normalized::No));
310impl_vertex_attribute!(u16, VertexAttribType::Unsigned(Normalized::No));
311impl_vertex_attribute!(u32, VertexAttribType::Unsigned(Normalized::No));
312impl_vertex_attribute!(f32, VertexAttribType::Floating);
313impl_vertex_attribute!(f64, VertexAttribType::Floating);
314impl_vertex_attribute!(bool, VertexAttribType::Boolean);