Skip to main content

vertex_struct

Macro vertex_struct 

Source
macro_rules! vertex_struct {
    { @step } => { ... };
    { @step $attr:ident } => { ... };
    { $struct:ident $( step $step:ident )? $( + $location:literal )? [
        $( $num:tt $field:ident => $attr:ident ),* $(,)?
    ] } => { ... };
}
Expand description

Define a vertex struct (to use in a vertex buffer).

Give each field a name and a standard vertex type from vertexformat. Also, you can optionally specify the wgpu::VertexStepMode, or omit the step ... part to default to Vertex.

If you use index buffers you may need to offset all the shader locations by a set value, if you have another active vertex buffer already taking some up. After the step you may specify a shader @location offset with + N, or omit it for no change (+ 0).

Note that fields must be numbered correctly, starting from 0 (even when the @location is offset). This is because I don’t know how to teach macros how to count and still be able to index tuples.
Also, the fields are not rearranged to be optimized to their alignment rules, though they should be padded correctly for vertex structs.

vertex_struct! { VertexStruct [
    0 pos => Float32x3,
    1 uv => Float32x2,
] }

// Continue off from vertex, offset shader location by 2 elements
vertex_struct! { InstanceStruct step Instance + 2 [
    0 int => Uint8,
    1 vec => Sint16x4,
    2 float => Float32,
] }

buffer! { VertexBuffer <VertexStruct> as VERTEX | COPY_DST }

// Big enough to store 10 VertexStructs, including padding if any
let buffer: VertexBuffer = context.new_buffer(10);

When you create a shader struct on the Rust side, its memory layout should match exactly as it is shader-side. You can write directly to each field (though everything’s in arrays) and then safely-ish transmute it to a byte slice to write to the buffer.

let single_struct: VertexStruct = (
    [5_i32],
    [0.0, 1.0, 2.0, 3.0],
    [4.0],
).into();
let mut lotsa_structs = [single_struct; 10];
*lotsa_structs[7].float = [5.0];

context.queue.write_buffer(
    &buffer,
    some_offset * size_of::<VertexStruct>() as u64,
    lotsa_structs.as_byte_slice(),
);