mew/vertexstruct.rs
1#[allow(unused_imports)]
2use crate::vertexformat;
3
4/// Define a vertex struct (to use in a **vertex** buffer).
5///
6/// Give each field a name and a standard vertex type from [`vertexformat`].
7/// Also, you can optionally specify the
8/// [`wgpu::VertexStepMode`](https://docs.rs/wgpu/latest/wgpu/enum.VertexStepMode.html),
9/// or omit the `step ...` part to default to `Vertex`.
10///
11/// If you use index buffers you may need to offset all the shader locations by
12/// a set value, if you have another active vertex buffer already taking some
13/// up. After the step you may specify a shader `@location` offset with `+ N`,
14/// or omit it for no change (`+ 0`).
15///
16/// Note that fields **must** be numbered correctly, starting from 0 (even when
17/// the `@location` is offset). This is because I don't know how to teach macros
18/// how to count and still be able to index tuples.
19/// Also, the fields are _not_ rearranged to be optimized to their alignment
20/// rules, though they should be padded correctly for vertex structs.
21///
22/// ```
23/// vertex_struct! { VertexStruct [
24/// 0 pos => Float32x3,
25/// 1 uv => Float32x2,
26/// ] }
27///
28/// // Continue off from vertex, offset shader location by 2 elements
29/// vertex_struct! { InstanceStruct step Instance + 2 [
30/// 0 int => Uint8,
31/// 1 vec => Sint16x4,
32/// 2 float => Float32,
33/// ] }
34///
35/// buffer! { VertexBuffer <VertexStruct> as VERTEX | COPY_DST }
36///
37/// // Big enough to store 10 VertexStructs, including padding if any
38/// let buffer: VertexBuffer = context.new_buffer(10);
39/// ```
40///
41/// When you create a shader struct on the Rust side, its memory layout should
42/// match exactly as it is shader-side. You can write directly to each field
43/// (though everything's in arrays) and then safely-ish transmute it to a byte
44/// slice to write to the buffer.
45///
46/// ```
47/// let single_struct: VertexStruct = (
48/// [5_i32],
49/// [0.0, 1.0, 2.0, 3.0],
50/// [4.0],
51/// ).into();
52/// let mut lotsa_structs = [single_struct; 10];
53/// *lotsa_structs[7].float = [5.0];
54///
55/// context.queue.write_buffer(
56/// &buffer,
57/// some_offset * size_of::<VertexStruct>() as u64,
58/// lotsa_structs.as_byte_slice(),
59/// );
60/// ```
61#[macro_export]
62macro_rules! vertex_struct {
63 { @step } => { $crate::wgpu::VertexStepMode::Vertex };
64 { @step $attr:ident } => { $crate::wgpu::VertexStepMode::$attr };
65
66 { $struct:ident $( step $step:ident )? $( + $location:literal )? [
67 $( $num:tt $field:ident => $attr:ident ),* $(,)?
68 ] } => {
69 #[derive(Clone, Debug, PartialEq, PartialOrd)]
70 #[repr(C, packed(2))]
71 pub struct $struct {
72 $( pub $field: $crate::vertexformat::$attr, )*
73 _padding: [u8; Self::PADDING],
74 }
75
76 impl $struct {
77 //pub const SUM_SIZE: usize = ::std::mem::size_of::<( $( $attr, )* )>();
78 //pub const SUM_SIZE: usize = sum_size! { $( $attr )* };
79 const SUM_SIZE: usize = {
80 #[repr(C, packed(2))]
81 struct SizeTest {
82 $( $field: $crate::vertexformat::$attr, )*
83 }
84 ::std::mem::size_of::<SizeTest>()
85 };
86 /// The total size of the struct, including padding for alignment.
87 pub const BYTES: usize = Self::SUM_SIZE.next_multiple_of(4);
88 /// The unused padding bytes necessary to bring the alignment up to a multiple of 4.
89 /// Aim to minimize this by rearranging members.
90 pub const PADDING: usize = Self::BYTES - Self::SUM_SIZE;
91 }
92
93 impl $crate::vertexstruct::MewVertexStruct for $struct {
94 type Bytes = [u8; Self::BYTES];
95 type Inners = ( $( <$crate::vertexformat::$attr as $crate::vertexformat::MewVertexFormat>::Inner , )* );
96 /*
97 type InnerRefs<'i> = ( $( &'i <$crate::vertexformat::$attr as $crate::vertexformat::MewVertexFormat>::Inner , )* );
98 type InnerMuts<'i> = ( $( &'i mut <$crate::vertexformat::$attr as $crate::vertexformat::MewVertexFormat>::Inner , )* );
99 */
100
101 fn from_inners(inners: Self::Inners) -> Self {
102 #[allow(unused_imports)]
103 use $crate::vertexformat::MewVertexFormat;
104 Self {
105 $( $field: $crate::vertexformat::$attr::from_inner(inners.$num), )*
106 _padding: [0; Self::PADDING],
107 }
108 }
109
110 fn from_bytes(bytes: Self::Bytes) -> Self {
111 unsafe { ::std::mem::transmute(bytes) }
112 }
113
114 fn zeroed() -> Self {
115 unsafe {
116 Self {
117 $( $field: ::std::mem::zeroed(), )*
118 _padding: [0; Self::PADDING],
119 }
120 }
121 }
122
123 // Probably not necessary...?
124 /*
125 fn get_refs(&self) -> Self::InnerRefs<'_> {
126 unsafe {
127 ( $( &*&raw const self.$field, )* )
128 }
129 }
130
131 fn get_muts(&mut self) -> Self::InnerMuts<'_> {
132 unsafe {
133 ( $( &mut *&raw mut self.$field, )* )
134 }
135 }
136 */
137
138 fn vertex_layout() -> $crate::wgpu::VertexBufferLayout<'static> {
139 static ATTRIBUTES: [$crate::wgpu::VertexAttribute; $crate::len! { $( $num )* }] = {
140 #[allow(unused_mut)]
141 let mut attrs = $crate::wgpu::vertex_attr_array![ $( $num => $attr , )* ];
142 $(
143 let mut i = 0;
144 while i < attrs.len() {
145 attrs[i].shader_location += $location;
146 i += 1;
147 }
148 )?
149 attrs
150 };
151
152 $crate::wgpu::VertexBufferLayout {
153 //array_stride: ::std::mem::size_of::<Self>() as u64,
154 array_stride: Self::BYTES as u64,
155 step_mode: $crate::vertex_struct! {@step $( $step )? },
156 attributes: &ATTRIBUTES,
157 }
158 }
159 }
160
161
162 impl From<[u8; Self::BYTES]> for $struct {
163 fn from(bytes: [u8; Self::BYTES]) -> Self {
164 use $crate::vertexstruct::MewVertexStruct;
165 Self::from_bytes(bytes)
166 }
167 }
168
169 impl From<( $( <$crate::vertexformat::$attr as $crate::vertexformat::MewVertexFormat>::Inner , )* )> for $struct {
170 fn from(inners: ( $( <$crate::vertexformat::$attr as $crate::vertexformat::MewVertexFormat>::Inner , )* )) -> Self {
171 use $crate::vertexstruct::MewVertexStruct;
172 Self::from_inners(inners)
173 }
174 }
175
176 impl AsRef<[u8; Self::BYTES]> for $struct {
177 fn as_ref(&self) -> &[u8; Self::BYTES] {
178 unsafe { ::std::mem::transmute(self) }
179 }
180 }
181 impl AsMut<[u8; Self::BYTES]> for $struct {
182 fn as_mut(&mut self) -> &mut [u8; Self::BYTES] {
183 unsafe { ::std::mem::transmute(self) }
184 }
185 }
186
187 // Why I manually did this, idk
188 /*
189 impl Clone for $struct {
190 fn clone(&self) -> Self {
191 unsafe {
192 Self {
193 $( $field: *&raw const self.$field, )*
194 _padding: [0; Self::PADDING],
195 }
196 }
197 }
198 }
199 */
200
201 impl Default for $struct {
202 fn default() -> Self {
203 use $crate::vertexstruct::MewVertexStruct;
204 Self::zeroed()
205 }
206 }
207 }
208}
209pub use vertex_struct;
210
211
212/// Trait for internal use to work with vertex structs.
213pub trait MewVertexStruct {
214 /// A byte array (`[u8; N]`) the same size as the struct.
215 type Bytes;
216 /// A tuple of all internal types.
217 type Inners;
218 /*
219 type InnerRefs<'i> where Self: 'i;
220 type InnerMuts<'i> where Self: 'i;
221 */
222 /// Build the struct using its internal types.
223 fn from_inners(inners: Self::Inners) -> Self;
224 /// Build the struct out of a byte array.
225 fn from_bytes(bytes: Self::Bytes) -> Self;
226 /// Build a struct with all fields zeroed.
227 fn zeroed() -> Self;
228 /*
229 fn get_refs<'i>(&'i self) -> Self::InnerRefs<'i>;
230 fn get_muts<'i>(&'i mut self) -> Self::InnerMuts<'i>;
231 */
232 /// Get this vertex struct's
233 /// [`wgpu::VertexBufferLayout`](https://docs.rs/wgpu/latest/wgpu/struct.VertexBufferLayout.html).
234 fn vertex_layout() -> wgpu::VertexBufferLayout<'static>;
235}
236
237
238/// Convenience trait to convert vertex struct slices directly to byte slices.
239///
240/// Automatically implemented on `&[S]` where `S` is any vertex struct.
241pub trait MewVertexStructByteSlice {
242 /// Get a byte slice to write directly to a buffer.
243 fn as_byte_slice(&self) -> &[u8];
244}
245
246impl<S: MewVertexStruct> MewVertexStructByteSlice for [S] {
247 fn as_byte_slice(&self) -> &[u8] {
248 unsafe {
249 std::slice::from_raw_parts(
250 self as *const [S] as *const u8,
251 size_of::<S>() * self.len(),
252 )
253 }
254 }
255}
256