1use derivative::Derivative;
4use gfx_hal::format::Format;
5use std::cmp::Ordering;
6use std::collections::HashMap;
7use std::{borrow::Cow, fmt::Debug};
8
9pub trait AsAttribute: Debug + PartialEq + PartialOrd + Copy + Send + Sync + 'static {
11 const NAME: &'static str;
13 const FORMAT: Format;
15}
16
17#[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
26pub 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 if let Some(val) = write_map.get(&(Cow::Borrowed(name), index, format)) {
40 return *val;
41 }
42
43 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#[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#[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#[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#[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#[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#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
145#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
146pub struct VertexFormat {
147 pub stride: u32,
149 pub attributes: Vec<Attribute>,
151}
152
153impl VertexFormat {
154 pub fn new<I: AsAttributes>(attrs: I) -> Self {
157 Self::with_opt_stride(attrs, None)
158 }
159
160 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 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
200pub trait AsAttributes {
202 type Iter: Iterator<Item = Attribute>;
204 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#[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
289type AttributeElem = gfx_hal::pso::Element<Format>;
291
292#[derive(Clone, Debug, Derivative)]
294#[derivative(PartialEq, Eq, Hash)]
295pub struct Attribute {
296 uuid: AttrUuid,
298 element: AttributeElem,
300 #[derivative(PartialEq = "ignore")]
302 #[derivative(Hash = "ignore")]
303 index: u8,
304 #[derivative(PartialEq = "ignore")]
306 #[derivative(Hash = "ignore")]
307 name: Cow<'static, str>,
308}
309
310impl Attribute {
311 pub fn uuid(&self) -> AttrUuid {
313 self.uuid
314 }
315 pub fn element(&self) -> &AttributeElem {
317 &self.element
318 }
319 pub fn index(&self) -> u8 {
321 self.index
322 }
323 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 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
441pub trait AsVertex: Debug + PartialEq + PartialOrd + Copy + Sized + Send + Sync + 'static {
443 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#[repr(C)]
458#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
459#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
460pub struct PosColor {
461 pub position: Position,
463 pub color: Color,
465}
466
467impl AsVertex for PosColor {
468 fn vertex() -> VertexFormat {
469 VertexFormat::new((Position::vertex(), Color::vertex()))
470 }
471}
472
473#[repr(C)]
475#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
476#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
477pub struct PosNorm {
478 pub position: Position,
480 pub normal: Normal,
482}
483
484impl AsVertex for PosNorm {
485 fn vertex() -> VertexFormat {
486 VertexFormat::new((Position::vertex(), Normal::vertex()))
487 }
488}
489
490#[repr(C)]
492#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
493#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
494pub struct PosColorNorm {
495 pub position: Position,
497 pub color: Color,
499 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#[repr(C)]
511#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
512#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
513pub struct PosTex {
514 pub position: Position,
516 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#[repr(C)]
528#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
529#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
530pub struct PosNormTex {
531 pub position: Position,
533 pub normal: Normal,
535 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#[repr(C)]
547#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
548#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
549pub struct PosNormTangTex {
550 pub position: Position,
552 pub normal: Normal,
554 pub tangent: Tangent,
556 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#[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);