Skip to main content

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