encase/types/
matrix.rs

1use crate::core::Metadata;
2
3pub trait MatrixScalar: crate::ShaderSize {}
4impl_marker_trait_for_f32!(MatrixScalar);
5
6pub struct MatrixMetadata {
7    pub col_padding: u64,
8}
9
10impl Metadata<MatrixMetadata> {
11    #[inline]
12    pub const fn col_padding(self) -> u64 {
13        self.extra.col_padding
14    }
15}
16
17/// Enables reading from the matrix (via `&[[T; R]; C]`)
18pub trait AsRefMatrixParts<T: MatrixScalar, const C: usize, const R: usize> {
19    fn as_ref_parts(&self) -> &[[T; R]; C];
20}
21
22/// Enables writing to the matrix (via `&mut [[T; R]; C]`)
23pub trait AsMutMatrixParts<T: MatrixScalar, const C: usize, const R: usize> {
24    fn as_mut_parts(&mut self) -> &mut [[T; R]; C];
25}
26
27/// Enables the creation of a matrix (via `[[T; R]; C]`)
28pub trait FromMatrixParts<T: MatrixScalar, const C: usize, const R: usize> {
29    fn from_parts(parts: [[T; R]; C]) -> Self;
30}
31
32/// Used to implement `ShaderType` for the given matrix type
33///
34/// The given matrix type should implement any combination of
35/// [`AsRefMatrixParts`], [`AsMutMatrixParts`], [`FromMatrixParts`]
36/// depending on needed capability (they can also be derived via `$using`)
37///
38/// # Args
39///
40/// - `$c` nr of columns the given matrix contains
41///
42/// - `$r` nr of rows the given matrix contains
43///
44/// - `$type` the type (representing a matrix) for which `ShaderType` will be implemented for
45///
46/// - `$generics` \[optional\] generics that will be passed into the `impl< >`
47///
48/// - `$el_type` \[optional\] inner element type of the matrix (should implement [`MatrixScalar`])
49///
50/// - `$using` \[optional\] can be any combination of `AsRef AsMut From`
51#[macro_export]
52macro_rules! impl_matrix {
53    ($c:literal, $r:literal, $type:ty $( ; using $($using:tt)* )?) => {
54        $crate::impl_matrix_inner!(__inner, ($c, $r, $type, T, (T)); $( $($using)* )?);
55    };
56    ($c:literal, $r:literal, $type:ty; ($($generics:tt)*) $( ; using $($using:tt)* )?) => {
57        $crate::impl_matrix_inner!(__inner, ($c, $r, $type, T, ($($generics)*)); $( $($using)* )?);
58    };
59    ($c:literal, $r:literal, $type:ty, $el_ty:ty $( ; using $($using:tt)* )?) => {
60        $crate::impl_matrix_inner!(__inner, ($c, $r, $type, $el_ty, ()); $( $($using)* )?);
61    };
62}
63
64#[doc(hidden)]
65#[macro_export]
66macro_rules! impl_matrix_inner {
67    (__inner, ($($other:tt)*); AsRef $($using:tt)*) => {
68        $crate::impl_matrix_inner!(__ref, $($other)*);
69        $crate::impl_matrix_inner!(__inner, ($($other)*); $($using)*);
70    };
71    (__inner, ($($other:tt)*); AsMut $($using:tt)*) => {
72        $crate::impl_matrix_inner!(__mut, $($other)*);
73        $crate::impl_matrix_inner!(__inner, ($($other)*); $($using)*);
74    };
75    (__inner, ($($other:tt)*); From $($using:tt)*) => {
76        $crate::impl_matrix_inner!(__from, $($other)*);
77        $crate::impl_matrix_inner!(__inner, ($($other)*); $($using)*);
78    };
79    (__inner, ($c:literal, $r:literal, $type:ty, $el_ty:ty, ($($generics:tt)*)); ) => {
80        $crate::impl_matrix_inner!(__main, $c, $r, $type, $el_ty, ($($generics)*));
81    };
82
83    (__ref, $c:literal, $r:literal, $type:ty, $el_ty:ty, ($($generics:tt)*)) => {
84        impl<$($generics)*> $crate::private::AsRefMatrixParts<$el_ty, $c, $r> for $type
85        where
86            Self: ::core::convert::AsRef<[[$el_ty; $r]; $c]>,
87            $el_ty: $crate::private::MatrixScalar,
88        {
89            #[inline]
90            fn as_ref_parts(&self) -> &[[$el_ty; $r]; $c] {
91                ::core::convert::AsRef::as_ref(self)
92            }
93        }
94    };
95    (__mut, $c:literal, $r:literal, $type:ty, $el_ty:ty, ($($generics:tt)*)) => {
96        impl<$($generics)*> $crate::private::AsMutMatrixParts<$el_ty, $c, $r> for $type
97        where
98            Self: ::core::convert::AsMut<[[$el_ty; $r]; $c]>,
99            $el_ty: $crate::private::MatrixScalar,
100        {
101            #[inline]
102            fn as_mut_parts(&mut self) -> &mut [[$el_ty; $r]; $c] {
103                ::core::convert::AsMut::as_mut(self)
104            }
105        }
106    };
107    (__from, $c:literal, $r:literal, $type:ty, $el_ty:ty, ($($generics:tt)*)) => {
108        impl<$($generics)*> $crate::private::FromMatrixParts<$el_ty, $c, $r> for $type
109        where
110            Self: ::core::convert::From<[[$el_ty; $r]; $c]>,
111            $el_ty: $crate::private::MatrixScalar,
112        {
113            #[inline]
114            fn from_parts(parts: [[$el_ty; $r]; $c]) -> Self {
115                ::core::convert::From::from(parts)
116            }
117        }
118    };
119
120    (__main, $c:literal, $r:literal, $type:ty, $el_ty:ty, ($($generics:tt)*)) => {
121        const _: () = assert!(
122            2 <= $c && $c <= 4,
123            "Matrix should have at least 2 columns and at most 4!",
124        );
125        const _: () = assert!(
126            2 <= $r && $r <= 4,
127            "Matrix should have at least 2 rows and at most 4!",
128        );
129
130        impl<$($generics)*> $crate::private::ShaderType for $type
131        where
132            $el_ty: $crate::private::ShaderSize,
133        {
134            type ExtraMetadata = $crate::private::MatrixMetadata;
135            const METADATA: $crate::private::Metadata<Self::ExtraMetadata> = {
136                let col_size = $crate::private::SizeValue::from(<$el_ty as $crate::private::ShaderSize>::SHADER_SIZE).mul($r);
137                let alignment = $crate::private::AlignmentValue::from_next_power_of_two_size(col_size);
138                let size = alignment.round_up_size(col_size).mul($c);
139                let col_padding = alignment.padding_needed_for(col_size.get());
140
141                $crate::private::Metadata {
142                    alignment,
143                    has_uniform_min_alignment: false,
144                    min_size: size,
145                    is_pod: <[$el_ty; $r] as $crate::private::ShaderType>::METADATA.is_pod() && col_padding == 0,
146                    extra: $crate::private::MatrixMetadata {
147                        col_padding,
148                    },
149                }
150            };
151        }
152
153        impl<$($generics)*> $crate::private::ShaderSize for $type
154        where
155            $el_ty: $crate::private::ShaderSize
156        {}
157
158        impl<$($generics)*> $crate::private::WriteInto for $type
159        where
160            Self: $crate::private::AsRefMatrixParts<$el_ty, $c, $r> + $crate::private::ShaderType<ExtraMetadata = $crate::private::MatrixMetadata>,
161            $el_ty: $crate::private::MatrixScalar + $crate::private::WriteInto,
162        {
163            #[inline]
164            fn write_into<B: $crate::private::BufferMut>(&self, writer: &mut $crate::private::Writer<B>) {
165                let columns = $crate::private::AsRefMatrixParts::<$el_ty, $c, $r>::as_ref_parts(self);
166
167                $crate::if_pod_and_little_endian!(if pod_and_little_endian {
168                    $crate::private::WriteInto::write_into(columns, writer);
169                } else {
170                    for col in columns {
171                        $crate::private::WriteInto::write_into(col, writer);
172                        writer.advance(<Self as $crate::private::ShaderType>::METADATA.col_padding() as ::core::primitive::usize);
173                    }
174                });
175            }
176        }
177
178        impl<$($generics)*> $crate::private::ReadFrom for $type
179        where
180            Self: $crate::private::AsMutMatrixParts<$el_ty, $c, $r> + $crate::private::ShaderType<ExtraMetadata = $crate::private::MatrixMetadata>,
181            $el_ty: $crate::private::MatrixScalar + $crate::private::ReadFrom,
182        {
183            #[inline]
184            fn read_from<B: $crate::private::BufferRef>(&mut self, reader: &mut $crate::private::Reader<B>) {
185                let columns = $crate::private::AsMutMatrixParts::<$el_ty, $c, $r>::as_mut_parts(self);
186
187                $crate::if_pod_and_little_endian!(if pod_and_little_endian {
188                    $crate::private::ReadFrom::read_from(columns, reader);
189                } else {
190                    for col in columns {
191                        $crate::private::ReadFrom::read_from(col, reader);
192                        reader.advance(<Self as $crate::private::ShaderType>::METADATA.col_padding() as ::core::primitive::usize);
193                    }
194                });
195            }
196        }
197
198        impl<$($generics)*> $crate::private::CreateFrom for $type
199        where
200            Self: $crate::private::FromMatrixParts<$el_ty, $c, $r> + $crate::private::ShaderType<ExtraMetadata = $crate::private::MatrixMetadata>,
201            $el_ty: $crate::private::MatrixScalar + $crate::private::CreateFrom,
202        {
203            #[inline]
204            fn create_from<B: $crate::private::BufferRef>(reader: &mut $crate::private::Reader<B>) -> Self {
205                let columns = $crate::if_pod_and_little_endian!(if pod_and_little_endian {
206                    $crate::private::CreateFrom::create_from(reader)
207                } else {
208                    ::core::array::from_fn(|_| {
209                        let col = $crate::private::CreateFrom::create_from(reader);
210                        reader.advance(<Self as $crate::private::ShaderType>::METADATA.col_padding() as ::core::primitive::usize);
211                        col
212                    })
213                });
214                $crate::private::FromMatrixParts::<$el_ty, $c, $r>::from_parts(columns)
215            }
216        }
217    };
218}