use std::{borrow::Cow, fmt::Debug};
pub type Attribute = gfx_hal::pso::Element<gfx_hal::format::Format>;
pub trait AsAttribute: Debug + PartialEq + PartialOrd + Copy + Send + Sync + 'static {
const NAME: &'static str;
const SIZE: u32;
const FORMAT: gfx_hal::format::Format;
}
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Position(pub [f32; 3]);
impl<T> From<T> for Position
where
T: Into<[f32; 3]>,
{
fn from(from: T) -> Self {
Position(from.into())
}
}
impl AsAttribute for Position {
const NAME: &'static str = "position";
const SIZE: u32 = 12;
const FORMAT: gfx_hal::format::Format = gfx_hal::format::Format::Rgb32Float;
}
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Color(pub [f32; 4]);
impl<T> From<T> for Color
where
T: Into<[f32; 4]>,
{
fn from(from: T) -> Self {
Color(from.into())
}
}
impl AsAttribute for Color {
const NAME: &'static str = "color";
const SIZE: u32 = 16;
const FORMAT: gfx_hal::format::Format = gfx_hal::format::Format::Rgba32Float;
}
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Normal(pub [f32; 3]);
impl<T> From<T> for Normal
where
T: Into<[f32; 3]>,
{
fn from(from: T) -> Self {
Normal(from.into())
}
}
impl AsAttribute for Normal {
const NAME: &'static str = "normal";
const SIZE: u32 = 12;
const FORMAT: gfx_hal::format::Format = gfx_hal::format::Format::Rgb32Float;
}
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Tangent(pub [f32; 3]);
impl<T> From<T> for Tangent
where
T: Into<[f32; 3]>,
{
fn from(from: T) -> Self {
Tangent(from.into())
}
}
impl AsAttribute for Tangent {
const NAME: &'static str = "tangent";
const SIZE: u32 = 12;
const FORMAT: gfx_hal::format::Format = gfx_hal::format::Format::Rgb32Float;
}
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TexCoord(pub [f32; 2]);
impl<T> From<T> for TexCoord
where
T: Into<[f32; 2]>,
{
fn from(from: T) -> Self {
TexCoord(from.into())
}
}
impl AsAttribute for TexCoord {
const NAME: &'static str = "tex_coord";
const SIZE: u32 = 8;
const FORMAT: gfx_hal::format::Format = gfx_hal::format::Format::Rg32Float;
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct VertexFormat<'a> {
pub attributes: Cow<'a, [Attribute]>,
pub stride: u32,
}
impl<'a> VertexFormat<'a> {
pub fn gfx_vertex_input_desc(
&self,
rate: gfx_hal::pso::InstanceRate,
) -> (
Vec<gfx_hal::pso::Element<gfx_hal::format::Format>>,
gfx_hal::pso::ElemStride,
gfx_hal::pso::InstanceRate,
) {
(self.attributes.clone().into_owned(), self.stride, rate)
}
}
pub trait AsVertex: Debug + PartialEq + PartialOrd + Copy + Sized + Send + Sync + 'static {
const VERTEX: VertexFormat<'static>;
#[inline]
fn attribute<F>() -> Attribute
where
F: AsAttribute,
Self: WithAttribute<F>,
{
<Self as WithAttribute<F>>::ATTRIBUTE
}
}
impl<T> AsVertex for T
where
T: AsAttribute,
{
const VERTEX: VertexFormat<'static> = VertexFormat {
attributes: Cow::Borrowed(&[Attribute {
format: T::FORMAT,
offset: 0,
}]),
stride: T::SIZE,
};
}
pub trait WithAttribute<F: AsAttribute>: AsVertex {
const ATTRIBUTE: Attribute;
}
impl<T> WithAttribute<T> for T
where
T: AsAttribute,
{
const ATTRIBUTE: Attribute = Attribute {
format: T::FORMAT,
offset: 0,
};
}
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PosColor {
pub position: Position,
pub color: Color,
}
impl AsVertex for PosColor {
const VERTEX: VertexFormat<'static> = VertexFormat {
attributes: Cow::Borrowed(&[
<Self as WithAttribute<Position>>::ATTRIBUTE,
<Self as WithAttribute<Color>>::ATTRIBUTE,
]),
stride: Position::SIZE + Color::SIZE,
};
}
impl WithAttribute<Position> for PosColor {
const ATTRIBUTE: Attribute = Attribute {
offset: 0,
format: Position::FORMAT,
};
}
impl WithAttribute<Color> for PosColor {
const ATTRIBUTE: Attribute = Attribute {
offset: Position::SIZE,
format: Color::FORMAT,
};
}
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PosNorm {
pub position: Position,
pub normal: Normal,
}
impl AsVertex for PosNorm {
const VERTEX: VertexFormat<'static> = VertexFormat {
attributes: Cow::Borrowed(&[
<Self as WithAttribute<Position>>::ATTRIBUTE,
<Self as WithAttribute<Normal>>::ATTRIBUTE,
]),
stride: Position::SIZE + Normal::SIZE,
};
}
impl WithAttribute<Position> for PosNorm {
const ATTRIBUTE: Attribute = Attribute {
offset: 0,
format: Position::FORMAT,
};
}
impl WithAttribute<Normal> for PosNorm {
const ATTRIBUTE: Attribute = Attribute {
offset: Position::SIZE,
format: Normal::FORMAT,
};
}
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PosColorNorm {
pub position: Position,
pub color: Color,
pub normal: Normal,
}
impl AsVertex for PosColorNorm {
const VERTEX: VertexFormat<'static> = VertexFormat {
attributes: Cow::Borrowed(&[
<Self as WithAttribute<Position>>::ATTRIBUTE,
<Self as WithAttribute<Color>>::ATTRIBUTE,
<Self as WithAttribute<Normal>>::ATTRIBUTE,
]),
stride: Position::SIZE + Color::SIZE + Normal::SIZE,
};
}
impl WithAttribute<Position> for PosColorNorm {
const ATTRIBUTE: Attribute = Attribute {
offset: 0,
format: Position::FORMAT,
};
}
impl WithAttribute<Color> for PosColorNorm {
const ATTRIBUTE: Attribute = Attribute {
offset: Position::SIZE,
format: Color::FORMAT,
};
}
impl WithAttribute<Normal> for PosColorNorm {
const ATTRIBUTE: Attribute = Attribute {
offset: Position::SIZE + Color::SIZE,
format: Normal::FORMAT,
};
}
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PosTex {
pub position: Position,
pub tex_coord: TexCoord,
}
impl AsVertex for PosTex {
const VERTEX: VertexFormat<'static> = VertexFormat {
attributes: Cow::Borrowed(&[
<Self as WithAttribute<Position>>::ATTRIBUTE,
<Self as WithAttribute<TexCoord>>::ATTRIBUTE,
]),
stride: Position::SIZE + TexCoord::SIZE,
};
}
impl WithAttribute<Position> for PosTex {
const ATTRIBUTE: Attribute = Attribute {
offset: 0,
format: Position::FORMAT,
};
}
impl WithAttribute<TexCoord> for PosTex {
const ATTRIBUTE: Attribute = Attribute {
offset: Position::SIZE,
format: TexCoord::FORMAT,
};
}
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PosNormTex {
pub position: Position,
pub normal: Normal,
pub tex_coord: TexCoord,
}
impl AsVertex for PosNormTex {
const VERTEX: VertexFormat<'static> = VertexFormat {
attributes: Cow::Borrowed(&[
<Self as WithAttribute<Position>>::ATTRIBUTE,
<Self as WithAttribute<Normal>>::ATTRIBUTE,
<Self as WithAttribute<TexCoord>>::ATTRIBUTE,
]),
stride: Position::SIZE + Normal::SIZE + TexCoord::SIZE,
};
}
impl WithAttribute<Position> for PosNormTex {
const ATTRIBUTE: Attribute = Attribute {
offset: 0,
format: Position::FORMAT,
};
}
impl WithAttribute<Normal> for PosNormTex {
const ATTRIBUTE: Attribute = Attribute {
offset: Position::SIZE,
format: Normal::FORMAT,
};
}
impl WithAttribute<TexCoord> for PosNormTex {
const ATTRIBUTE: Attribute = Attribute {
offset: Position::SIZE + Normal::SIZE,
format: TexCoord::FORMAT,
};
}
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PosNormTangTex {
pub position: Position,
pub normal: Normal,
pub tangent: Tangent,
pub tex_coord: TexCoord,
}
impl AsVertex for PosNormTangTex {
const VERTEX: VertexFormat<'static> = VertexFormat {
attributes: Cow::Borrowed(&[
<Self as WithAttribute<Position>>::ATTRIBUTE,
<Self as WithAttribute<Normal>>::ATTRIBUTE,
<Self as WithAttribute<Tangent>>::ATTRIBUTE,
<Self as WithAttribute<TexCoord>>::ATTRIBUTE,
]),
stride: Position::SIZE + Normal::SIZE + Tangent::SIZE + TexCoord::SIZE,
};
}
impl WithAttribute<Position> for PosNormTangTex {
const ATTRIBUTE: Attribute = Attribute {
offset: 0,
format: Position::FORMAT,
};
}
impl WithAttribute<Normal> for PosNormTangTex {
const ATTRIBUTE: Attribute = Attribute {
offset: Position::SIZE,
format: Normal::FORMAT,
};
}
impl WithAttribute<Tangent> for PosNormTangTex {
const ATTRIBUTE: Attribute = Attribute {
offset: Position::SIZE + Normal::SIZE,
format: Tangent::FORMAT,
};
}
impl WithAttribute<TexCoord> for PosNormTangTex {
const ATTRIBUTE: Attribute = Attribute {
offset: Position::SIZE + Normal::SIZE + Tangent::SIZE,
format: TexCoord::FORMAT,
};
}
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub struct Transform(pub [[f32; 4]; 4]);
impl<T> From<T> for Transform
where
T: Into<[[f32; 4]; 4]>,
{
fn from(from: T) -> Self {
Transform(from.into())
}
}
impl AsVertex for Transform {
const VERTEX: VertexFormat<'static> = VertexFormat {
attributes: Cow::Borrowed(&[
Attribute {
format: gfx_hal::format::Format::Rgba32Float,
offset: 0,
},
Attribute {
format: gfx_hal::format::Format::Rgba32Float,
offset: 16,
},
Attribute {
format: gfx_hal::format::Format::Rgba32Float,
offset: 32,
},
Attribute {
format: gfx_hal::format::Format::Rgba32Float,
offset: 48,
},
]),
stride: 64,
};
}
pub trait Query<T>: AsVertex {
const QUERIED_ATTRIBUTES: &'static [(&'static str, Attribute)];
}
macro_rules! impl_query {
($($a:ident),*) => {
impl<VF $(,$a)*> Query<($($a,)*)> for VF
where VF: AsVertex,
$(
$a: AsAttribute,
VF: WithAttribute<$a>,
)*
{
const QUERIED_ATTRIBUTES: &'static [(&'static str, Attribute)] = &[
$(
($a::NAME, <VF as WithAttribute<$a>>::ATTRIBUTE),
)*
];
}
impl_query!(@ $($a),*);
};
(@) => {};
(@ $head:ident $(,$tail:ident)*) => {
impl_query!($($tail),*);
};
}
impl_query!(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);