1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
//! Primitive assembly for the graphics pipeline.

pub use gfx_hal::pso::Element as VertexElement;
use gfx_hal::pso::{
  self,
  AttributeDesc,
  VertexBufferDesc,
};

use super::{
  buffer::Buffer,
  surface::ColorFormat,
};

/// Attributes for a vertex.
#[derive(Debug, Clone)]
pub struct VertexAttribute {
  pub location: u32,
  pub offset: u32,
  pub element: VertexElement<ColorFormat>,
}

/// PrimitiveAssemblerBuilder for preparing PrimitiveAssemblers to use in the
/// lambda-platform Rendering pipeline.
pub struct PrimitiveAssemblerBuilder {
  buffer_descriptions: Vec<VertexBufferDesc>,
  attribute_descriptions: Vec<AttributeDesc>,
}

impl PrimitiveAssemblerBuilder {
  pub fn new() -> Self {
    return Self {
      buffer_descriptions: Vec::new(),
      attribute_descriptions: Vec::new(),
    };
  }

  /// Build a primitive assembler given the lambda-platform vertex shader
  /// module. Buffers & attributes do not have to be tied to
  pub fn build<'shader, RenderBackend: gfx_hal::Backend>(
    &'shader mut self,
    vertex_shader: &'shader super::shader::ShaderModule<RenderBackend>,
    buffers: Option<&Vec<&Buffer<RenderBackend>>>,
    attributes: Option<&[VertexAttribute]>,
  ) -> PrimitiveAssembler<'shader, RenderBackend> {
    let binding = self.buffer_descriptions.len() as u32;

    match (buffers, attributes) {
      (Some(buffers), Some(attributes)) => {
        println!(
          "[DEBUG] Building primitive assembler with buffers and attributes"
        );
        self.buffer_descriptions = buffers
          .iter()
          .map(|buffer| VertexBufferDesc {
            binding,
            stride: buffer.stride() as u32,
            rate: pso::VertexInputRate::Vertex,
          })
          .collect();

        self.attribute_descriptions = attributes
          .iter()
          .map(|attribute| {
            return AttributeDesc {
              location: attribute.location,
              binding,
              element: attribute.element,
            };
          })
          .collect();
      }
      _ => {}
    }

    let primitive_assembler = pso::PrimitiveAssemblerDesc::Vertex {
      buffers: self.buffer_descriptions.as_slice(),
      attributes: self.attribute_descriptions.as_slice(),
      input_assembler: pso::InputAssemblerDesc::new(
        pso::Primitive::TriangleList,
      ),
      vertex: pso::EntryPoint {
        entry: vertex_shader.entry(),
        module: super::internal::module_for(vertex_shader),
        specialization: vertex_shader.specializations().clone(),
      },
      tessellation: None,
      geometry: None,
    };

    return PrimitiveAssembler::<'shader> {
      primitive_assembler,
    };
  }
}

/// PrimitiveAssembler for used for describing how Vertex Shaders should
/// construct primitives. Each constructed Primitive Assembler should be alive
/// for as long as the shader module that created it is.
pub struct PrimitiveAssembler<'shader, RenderBackend: gfx_hal::Backend> {
  primitive_assembler: pso::PrimitiveAssemblerDesc<'shader, RenderBackend>,
}

impl<'shader, RenderBackend: gfx_hal::Backend>
  PrimitiveAssembler<'shader, RenderBackend>
{
  // Get the internal primitive assembler.
  pub(super) fn internal_primitive_assembler(
    self,
  ) -> pso::PrimitiveAssemblerDesc<'shader, RenderBackend> {
    return self.primitive_assembler;
  }
}