rendy_util/types/
vertex.rs

1//! Built-in vertex formats.
2
3use derivative::Derivative;
4use gfx_hal::format::Format;
5use std::cmp::Ordering;
6use std::collections::HashMap;
7use std::{borrow::Cow, fmt::Debug};
8
9/// Trait for vertex attributes to implement
10pub trait AsAttribute: Debug + PartialEq + PartialOrd + Copy + Send + Sync + 'static {
11    /// Name of the attribute
12    const NAME: &'static str;
13    /// Attribute format.
14    const FORMAT: Format;
15}
16
17/// A unique identifier for vertex attribute of given name, format and array index.
18#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
19pub struct AttrUuid(u16);
20
21lazy_static::lazy_static! {
22    static ref UUID_MAP: parking_lot::RwLock<HashMap<(Cow<'static, str>, u8, Format), AttrUuid>> =
23        Default::default();
24}
25
26/// Retreive a unique identifier for vertex attribute of given name, format and array index.
27///
28/// Non-array attributes should always use index 0.
29/// Matrices and arrays must be specified as a series of attributes with the same name and consecutive indices.
30pub fn attribute_uuid(name: &str, index: u8, format: Format) -> AttrUuid {
31    let read_map = UUID_MAP.read();
32    if let Some(val) = read_map.get(&(Cow::Borrowed(name), index, format)) {
33        return *val;
34    }
35    drop(read_map);
36
37    let mut write_map = UUID_MAP.write();
38    // First check again if value was not written by previous owner of the lock.
39    if let Some(val) = write_map.get(&(Cow::Borrowed(name), index, format)) {
40        return *val;
41    }
42
43    // uuid 0 is reserved for unused attribute indices
44    let val = AttrUuid(write_map.len() as u16 + 1);
45    write_map.insert((Cow::Owned(name.to_owned()), index, format), val);
46    val
47}
48
49/// Type for position attribute of vertex.
50#[repr(transparent)]
51#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
52#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
53pub struct Position(pub [f32; 3]);
54impl<T> From<T> for Position
55where
56    T: Into<[f32; 3]>,
57{
58    fn from(from: T) -> Self {
59        Position(from.into())
60    }
61}
62impl AsAttribute for Position {
63    const NAME: &'static str = "position";
64    const FORMAT: Format = Format::Rgb32Sfloat;
65}
66
67/// Type for color attribute of vertex
68#[repr(transparent)]
69#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
70#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
71pub struct Color(pub [f32; 4]);
72impl<T> From<T> for Color
73where
74    T: Into<[f32; 4]>,
75{
76    fn from(from: T) -> Self {
77        Color(from.into())
78    }
79}
80impl AsAttribute for Color {
81    const NAME: &'static str = "color";
82    const FORMAT: Format = Format::Rgba32Sfloat;
83}
84
85/// Type for texture coord attribute of vertex
86#[repr(transparent)]
87#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
88#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
89pub struct Normal(pub [f32; 3]);
90impl<T> From<T> for Normal
91where
92    T: Into<[f32; 3]>,
93{
94    fn from(from: T) -> Self {
95        Normal(from.into())
96    }
97}
98
99impl AsAttribute for Normal {
100    const NAME: &'static str = "normal";
101    const FORMAT: Format = Format::Rgb32Sfloat;
102}
103
104/// Type for tangent attribute of vertex. W represents handedness and should always be 1 or -1
105#[repr(transparent)]
106#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
107#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
108pub struct Tangent(pub [f32; 4]);
109impl<T> From<T> for Tangent
110where
111    T: Into<[f32; 4]>,
112{
113    fn from(from: T) -> Self {
114        Tangent(from.into())
115    }
116}
117
118impl AsAttribute for Tangent {
119    const NAME: &'static str = "tangent";
120    const FORMAT: Format = Format::Rgba32Sfloat;
121}
122
123/// Type for texture coord attribute of vertex
124#[repr(transparent)]
125#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
126#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
127pub struct TexCoord(pub [f32; 2]);
128impl<T> From<T> for TexCoord
129where
130    T: Into<[f32; 2]>,
131{
132    fn from(from: T) -> Self {
133        TexCoord(from.into())
134    }
135}
136
137impl AsAttribute for TexCoord {
138    const NAME: &'static str = "tex_coord";
139    const FORMAT: Format = Format::Rg32Sfloat;
140}
141
142/// Vertex format contains information to initialize graphics pipeline
143/// Attributes must be sorted by offset.
144#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
145#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
146pub struct VertexFormat {
147    /// Size of single vertex.
148    pub stride: u32,
149    /// Attributes for format.
150    pub attributes: Vec<Attribute>,
151}
152
153impl VertexFormat {
154    /// Create new vertex format with specified attributes.
155    /// The max attribute offset and format size is used to calculate the stricde.
156    pub fn new<I: AsAttributes>(attrs: I) -> Self {
157        Self::with_opt_stride(attrs, None)
158    }
159
160    /// Create new vertex format with specified attributes and manually specified stride.
161    pub fn with_stride<I: AsAttributes>(attrs: I, stride: u32) -> Self {
162        Self::with_opt_stride(attrs, Some(stride))
163    }
164
165    fn with_opt_stride<I: AsAttributes>(attrs: I, stride: Option<u32>) -> Self {
166        let mut attributes: Vec<Attribute> = attrs.attributes().collect();
167        attributes.sort_unstable();
168        let stride = stride.unwrap_or_else(|| {
169            attributes
170                .iter()
171                .map(|attr| {
172                    (attr.element.offset + attr.element.format.surface_desc().bits as u32 / 8)
173                })
174                .max()
175                .expect("Vertex format cannot be empty")
176        });
177        Self { stride, attributes }
178    }
179
180    /// Convert into gfx digestible type.
181    pub fn gfx_vertex_input_desc(
182        &self,
183        rate: gfx_hal::pso::VertexInputRate,
184    ) -> (
185        Vec<gfx_hal::pso::Element<Format>>,
186        gfx_hal::pso::ElemStride,
187        gfx_hal::pso::VertexInputRate,
188    ) {
189        (
190            self.attributes
191                .iter()
192                .map(|attr| attr.element.clone())
193                .collect(),
194            self.stride,
195            rate,
196        )
197    }
198}
199
200/// Represent types that can be interpreted as list of vertex attributes.
201pub trait AsAttributes {
202    /// The iterator type for retreived attributes
203    type Iter: Iterator<Item = Attribute>;
204    /// Retreive a list of vertex attributes with offsets relative to beginning of that list
205    fn attributes(self) -> Self::Iter;
206}
207
208impl AsAttributes for Vec<Attribute> {
209    type Iter = std::vec::IntoIter<Attribute>;
210    fn attributes(self) -> Self::Iter {
211        self.into_iter()
212    }
213}
214
215impl AsAttributes for VertexFormat {
216    type Iter = std::vec::IntoIter<Attribute>;
217    fn attributes(self) -> Self::Iter {
218        self.attributes.into_iter()
219    }
220}
221
222/// An iterator adapter that generates a list of attributes with given formats and names
223#[derive(Debug)]
224pub struct AttrGenIter<N: Into<Cow<'static, str>>, I: Iterator<Item = (Format, N)>> {
225    inner: I,
226    offset: u32,
227    index: u8,
228    prev_name: Option<Cow<'static, str>>,
229}
230
231impl<N: Into<Cow<'static, str>>, I: Iterator<Item = (Format, N)>> AttrGenIter<N, I> {
232    fn new(iter: I) -> Self {
233        AttrGenIter {
234            inner: iter,
235            offset: 0,
236            index: 0,
237            prev_name: None,
238        }
239    }
240}
241
242impl<N: Into<Cow<'static, str>>, I: Iterator<Item = (Format, N)>> Iterator for AttrGenIter<N, I> {
243    type Item = Attribute;
244    fn next(&mut self) -> Option<Self::Item> {
245        self.inner.next().map(|data| {
246            let (format, name) = data;
247            let name: Cow<'static, str> = name.into();
248            if self.prev_name.as_ref().map(|n| n == &name).unwrap_or(false) {
249                self.index += 1;
250            } else {
251                self.prev_name.replace(name.clone());
252                self.index = 0;
253            }
254            let this_offset = self.offset;
255            self.offset += format.surface_desc().bits as u32 / 8;
256            Attribute::new(
257                name,
258                self.index,
259                AttributeElem {
260                    format,
261                    offset: this_offset,
262                },
263            )
264        })
265    }
266}
267
268impl<N: Into<Cow<'static, str>>> AsAttributes for Vec<(Format, N)> {
269    type Iter = AttrGenIter<N, std::vec::IntoIter<(Format, N)>>;
270    fn attributes(self) -> Self::Iter {
271        AttrGenIter::new(self.into_iter())
272    }
273}
274
275impl<N: Into<Cow<'static, str>>> AsAttributes for Option<(Format, N)> {
276    type Iter = AttrGenIter<N, std::option::IntoIter<(Format, N)>>;
277    fn attributes(self) -> Self::Iter {
278        AttrGenIter::new(self.into_iter())
279    }
280}
281
282impl<N: Into<Cow<'static, str>>> AsAttributes for (Format, N) {
283    type Iter = AttrGenIter<N, std::option::IntoIter<(Format, N)>>;
284    fn attributes(self) -> Self::Iter {
285        AttrGenIter::new(Some(self).into_iter())
286    }
287}
288
289/// raw hal type for vertex attribute
290type AttributeElem = gfx_hal::pso::Element<Format>;
291
292/// Vertex attribute type.
293#[derive(Clone, Debug, Derivative)]
294#[derivative(PartialEq, Eq, Hash)]
295pub struct Attribute {
296    /// globally unique identifier for attribute's semantic
297    uuid: AttrUuid,
298    /// hal type with offset and format
299    element: AttributeElem,
300    /// Attribute array index. Matrix attributes are treated like array of vectors.
301    #[derivative(PartialEq = "ignore")]
302    #[derivative(Hash = "ignore")]
303    index: u8,
304    /// Attribute name as used in the shader
305    #[derivative(PartialEq = "ignore")]
306    #[derivative(Hash = "ignore")]
307    name: Cow<'static, str>,
308}
309
310impl Attribute {
311    /// globally unique identifier for attribute's semantic
312    pub fn uuid(&self) -> AttrUuid {
313        self.uuid
314    }
315    /// hal type with offset and format
316    pub fn element(&self) -> &AttributeElem {
317        &self.element
318    }
319    /// Attribute array index. Matrix attributes are treated like array of vectors.
320    pub fn index(&self) -> u8 {
321        self.index
322    }
323    /// Attribute name as used in the shader
324    pub fn name(&self) -> &str {
325        &self.name
326    }
327}
328
329impl PartialOrd for Attribute {
330    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
331        Some(
332            self.element
333                .offset
334                .cmp(&other.element.offset)
335                .then_with(|| self.name.cmp(&other.name))
336                .then_with(|| self.index.cmp(&other.index)),
337        )
338    }
339}
340
341impl Ord for Attribute {
342    fn cmp(&self, other: &Self) -> Ordering {
343        self.partial_cmp(other).unwrap()
344    }
345}
346
347#[cfg(feature = "serde")]
348mod serde_attribute {
349    use serde::{
350        de::{Error, MapAccess, Visitor},
351        ser::SerializeStruct,
352        Deserialize, Deserializer, Serialize, Serializer,
353    };
354
355    impl Serialize for super::Attribute {
356        fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
357            let mut s = serializer.serialize_struct("Attribute", 3)?;
358            s.serialize_field("element", &self.element)?;
359            s.serialize_field("index", &self.index)?;
360            s.serialize_field("name", &self.name)?;
361            s.end()
362        }
363    }
364
365    impl<'de> Deserialize<'de> for super::Attribute {
366        fn deserialize<D>(deserializer: D) -> Result<super::Attribute, D::Error>
367        where
368            D: Deserializer<'de>,
369        {
370            #[derive(Deserialize)]
371            #[serde(field_identifier, rename_all = "lowercase")]
372            enum Field {
373                Element,
374                Index,
375                Name,
376            }
377
378            struct AttributeVisitor;
379            impl<'de> Visitor<'de> for AttributeVisitor {
380                type Value = super::Attribute;
381                fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
382                    formatter.write_str("Attribute struct")
383                }
384                fn visit_map<V: MapAccess<'de>>(
385                    self,
386                    mut map: V,
387                ) -> Result<super::Attribute, V::Error> {
388                    let mut element = None;
389                    let mut index = None;
390                    let mut name: Option<&'de str> = None;
391                    while let Some(key) = map.next_key()? {
392                        match key {
393                            Field::Element => {
394                                if element.is_some() {
395                                    return Err(Error::duplicate_field("element"));
396                                }
397                                element.replace(map.next_value()?);
398                            }
399                            Field::Index => {
400                                if index.is_some() {
401                                    return Err(Error::duplicate_field("index"));
402                                }
403                                index.replace(map.next_value()?);
404                            }
405                            Field::Name => {
406                                if name.is_some() {
407                                    return Err(Error::duplicate_field("name"));
408                                }
409                                name.replace(map.next_value()?);
410                            }
411                        }
412                    }
413                    let element = element.ok_or_else(|| Error::missing_field("element"))?;
414                    let index = index.ok_or_else(|| Error::missing_field("index"))?;
415                    let name = name.ok_or_else(|| Error::missing_field("name"))?;
416                    Ok(super::Attribute::new(String::from(name), index, element))
417                }
418            }
419            deserializer.deserialize_struct(
420                "Attribute",
421                &["element", "index", "name"],
422                AttributeVisitor,
423            )
424        }
425    }
426}
427
428impl Attribute {
429    /// Define new vertex attribute with given name and array index. Use index 0 for non-array attributes.
430    pub fn new(name: impl Into<Cow<'static, str>>, index: u8, element: AttributeElem) -> Self {
431        let name = name.into();
432        Self {
433            uuid: attribute_uuid(&name, index, element.format),
434            element,
435            index,
436            name: name.into(),
437        }
438    }
439}
440
441/// Trait implemented by all valid vertex formats.
442pub trait AsVertex: Debug + PartialEq + PartialOrd + Copy + Sized + Send + Sync + 'static {
443    /// List of all attributes formats with name and offset.
444    fn vertex() -> VertexFormat;
445}
446
447impl<T> AsVertex for T
448where
449    T: AsAttribute,
450{
451    fn vertex() -> VertexFormat {
452        VertexFormat::new(Some((T::FORMAT, T::NAME)))
453    }
454}
455
456/// Vertex format with position and RGBA8 color attributes.
457#[repr(C)]
458#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
459#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
460pub struct PosColor {
461    /// Position of the vertex in 3D space.
462    pub position: Position,
463    /// RGBA color value of the vertex.
464    pub color: Color,
465}
466
467impl AsVertex for PosColor {
468    fn vertex() -> VertexFormat {
469        VertexFormat::new((Position::vertex(), Color::vertex()))
470    }
471}
472
473/// Vertex format with position and normal attributes.
474#[repr(C)]
475#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
476#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
477pub struct PosNorm {
478    /// Position of the vertex in 3D space.
479    pub position: Position,
480    /// Normal vector of the vertex.
481    pub normal: Normal,
482}
483
484impl AsVertex for PosNorm {
485    fn vertex() -> VertexFormat {
486        VertexFormat::new((Position::vertex(), Normal::vertex()))
487    }
488}
489
490/// Vertex format with position, color and normal attributes.
491#[repr(C)]
492#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
493#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
494pub struct PosColorNorm {
495    /// Position of the vertex in 3D space.
496    pub position: Position,
497    /// RGBA color value of the vertex.
498    pub color: Color,
499    /// Normal vector of the vertex.
500    pub normal: Normal,
501}
502
503impl AsVertex for PosColorNorm {
504    fn vertex() -> VertexFormat {
505        VertexFormat::new((Position::vertex(), Color::vertex(), Normal::vertex()))
506    }
507}
508
509/// Vertex format with position and UV texture coordinate attributes.
510#[repr(C)]
511#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
512#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
513pub struct PosTex {
514    /// Position of the vertex in 3D space.
515    pub position: Position,
516    /// UV texture coordinates used by the vertex.
517    pub tex_coord: TexCoord,
518}
519
520impl AsVertex for PosTex {
521    fn vertex() -> VertexFormat {
522        VertexFormat::new((Position::vertex(), TexCoord::vertex()))
523    }
524}
525
526/// Vertex format with position, normal and UV texture coordinate attributes.
527#[repr(C)]
528#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
529#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
530pub struct PosNormTex {
531    /// Position of the vertex in 3D space.
532    pub position: Position,
533    /// Normal vector of the vertex.
534    pub normal: Normal,
535    /// UV texture coordinates used by the vertex.
536    pub tex_coord: TexCoord,
537}
538
539impl AsVertex for PosNormTex {
540    fn vertex() -> VertexFormat {
541        VertexFormat::new((Position::vertex(), Normal::vertex(), TexCoord::vertex()))
542    }
543}
544
545/// Vertex format with position, normal, tangent, and UV texture coordinate attributes.
546#[repr(C)]
547#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
548#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
549pub struct PosNormTangTex {
550    /// Position of the vertex in 3D space.
551    pub position: Position,
552    /// Normal vector of the vertex.
553    pub normal: Normal,
554    /// Tangent vector of the vertex.
555    pub tangent: Tangent,
556    /// UV texture coordinates used by the vertex.
557    pub tex_coord: TexCoord,
558}
559
560impl AsVertex for PosNormTangTex {
561    fn vertex() -> VertexFormat {
562        VertexFormat::new((
563            (Position::vertex()),
564            (Normal::vertex()),
565            (Tangent::vertex()),
566            (TexCoord::vertex()),
567        ))
568    }
569}
570
571/// Full vertex transformation attribute.
572/// Typically provided on per-instance basis.
573/// It takes 4 attribute locations.
574#[repr(transparent)]
575#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
576pub struct Model(pub [[f32; 4]; 4]);
577impl<T> From<T> for Model
578where
579    T: Into<[[f32; 4]; 4]>,
580{
581    fn from(from: T) -> Self {
582        Model(from.into())
583    }
584}
585
586impl AsVertex for Model {
587    fn vertex() -> VertexFormat {
588        VertexFormat::new((
589            (Format::Rgba32Sfloat, "model"),
590            (Format::Rgba32Sfloat, "model"),
591            (Format::Rgba32Sfloat, "model"),
592            (Format::Rgba32Sfloat, "model"),
593        ))
594    }
595}
596
597macro_rules! impl_as_attributes {
598    ($($a:ident),*) => {
599        impl<$($a),*> AsAttributes for ($($a,)*) where $($a: AsAttributes),* {
600            type Iter = std::vec::IntoIter<Attribute>;
601            fn attributes(self) -> Self::Iter {
602                let _offset: u32 = 0;
603                let mut _attrs: Vec<Attribute> = Vec::new();
604                #[allow(non_snake_case)]
605                let ($($a,)*) = self;
606                $(
607                    let mut next_offset = _offset;
608                    let v = $a.attributes();
609                    _attrs.extend(v.map(|mut attr| {
610                        attr.element.offset += _offset;
611                        next_offset = next_offset.max(attr.element.offset + attr.element.format.surface_desc().bits as u32 / 8);
612                        attr
613                    }));
614                    let _offset = next_offset;
615                )*
616                _attrs.into_iter()
617            }
618        }
619
620        impl_as_attributes!(@ $($a),*);
621    };
622    (@) => {};
623    (@ $head:ident $(,$tail:ident)*) => {
624        impl_as_attributes!($($tail),*);
625    };
626}
627
628impl_as_attributes!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z);