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);