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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//! Mesh Implementation

use lambda_platform::obj::load_textured_obj_from_file;

use super::{
  vertex::{
    Vertex,
    VertexAttribute,
    VertexElement,
  },
  ColorFormat,
};

// ---------------------------------- Mesh ------------------------------------

/// Collection of vertices and indices that define a 3D object.
#[derive(Debug)]
pub struct Mesh {
  vertices: Vec<Vertex>,
  attributes: Vec<VertexAttribute>,
}

impl Mesh {
  /// Gets the vertices of the mesh.
  pub fn vertices(&self) -> &[Vertex] {
    &self.vertices
  }

  /// Gets the attributes of the mesh.
  pub fn attributes(&self) -> &[VertexAttribute] {
    &self.attributes
  }
}

// ------------------------------ MeshBuilder ---------------------------------

/// Construction for a mesh.
#[derive(Clone, Debug)]
pub struct MeshBuilder {
  capacity: usize,
  vertices: Vec<Vertex>,
  attributes: Vec<VertexAttribute>,
}

impl MeshBuilder {
  /// Creates a new mesh builder.
  pub fn new() -> Self {
    return Self {
      capacity: 0,
      vertices: Vec::new(),
      attributes: Vec::new(),
    };
  }

  /// Allocates memory for the given number of vertices and fills
  /// the mesh with empty vertices.
  pub fn with_capacity(&mut self, size: usize) -> &mut Self {
    self.capacity = size;
    self.vertices.resize(
      size,
      Vertex {
        position: [0.0, 0.0, 0.0],
        normal: [0.0, 0.0, 0.0],
        color: [0.0, 0.0, 0.0],
      },
    );
    return self;
  }

  /// Adds a vertex to the mesh.
  pub fn with_vertex(&mut self, vertex: Vertex) -> &mut Self {
    self.vertices.push(vertex);
    return self;
  }

  /// Specify the attributes of the mesh. This is used to map the vertex data to
  /// the input of the vertex shader.
  pub fn with_attributes(
    &mut self,
    attributes: Vec<VertexAttribute>,
  ) -> &mut Self {
    self.attributes = attributes;
    return self;
  }

  /// Builds a mesh from the vertices and indices that have been added to the
  /// builder and allocates the memory for the mesh on the GPU.
  pub fn build(&self) -> Mesh {
    return Mesh {
      vertices: self.vertices.clone(),
      attributes: self.attributes.clone(),
    };
  }

  /// Builds a mesh from the vertices of an OBJ file. The mesh will have the same
  /// attributes as the OBJ file and can be allocated on to the GPU with
  /// `BufferBuilder::build_from_mesh`.
  pub fn build_from_obj(&self, file_path: &str) -> Mesh {
    let obj = load_textured_obj_from_file(file_path);

    let vertices = obj
      .vertices
      .iter()
      .map(|v| {
        return Vertex {
          position: v.position,
          normal: v.normal,
          color: [1.0, 1.0, 1.0],
        };
      })
      .collect::<Vec<Vertex>>();

    // Returns a mesh with the given vertices with attributes for position,
    // normal, and color.
    return Mesh {
      vertices,
      attributes: vec![
        VertexAttribute {
          location: 0,
          offset: 0,
          element: VertexElement {
            format: ColorFormat::Rgb32Sfloat,
            offset: 0,
          },
        },
        VertexAttribute {
          location: 1,
          offset: 0,
          element: VertexElement {
            format: ColorFormat::Rgb32Sfloat,
            offset: 12,
          },
        },
        VertexAttribute {
          location: 2,
          offset: 0,
          element: VertexElement {
            format: ColorFormat::Rgb32Sfloat,
            offset: 24,
          },
        },
      ],
    };
  }
}

#[cfg(test)]
mod tests {
  #[test]
  fn mesh_building() {
    let mut mesh = super::MeshBuilder::new();

    assert_eq!(mesh.vertices.len(), 0);
  }
}