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
17pub trait AsRefMatrixParts<T: MatrixScalar, const C: usize, const R: usize> {
19 fn as_ref_parts(&self) -> &[[T; R]; C];
20}
21
22pub trait AsMutMatrixParts<T: MatrixScalar, const C: usize, const R: usize> {
24 fn as_mut_parts(&mut self) -> &mut [[T; R]; C];
25}
26
27pub trait FromMatrixParts<T: MatrixScalar, const C: usize, const R: usize> {
29 fn from_parts(parts: [[T; R]; C]) -> Self;
30}
31
32#[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}