moon_engine/
mesh.rs

1//! The definitions of [`Vertex`], [`Mesh`] and their implementations.
2
3use web_sys::{WebGlBuffer, WebGlVertexArrayObject};
4
5use crate::{gl, GL};
6
7/// The `Vertex` struct holds the data that will be later sent to WebGL in a `GL::ARRAY_BUFFER`.
8/// It consists of position and color vectors, and UV co-ordinates.
9#[derive(Debug, Clone, Copy)]
10#[repr(C)]
11pub struct Vertex {
12    /// A two component array of [`f32`], representing the position of the [`Vertex`].
13    pub position: [f32; 2],
14    /// A two component array of [`f32`], representing the UV co-ordinates of the [`Vertex`].
15    pub uv: [f32; 2],
16    /// A four component array of [`f32`], representing the color of the [`Vertex`].
17    pub color: [f32; 4],
18}
19
20impl Default for Vertex {
21    fn default() -> Self {
22        Self {
23            position: [0.0, 0.0],
24            uv: [0.0, 0.0],
25            color: [1.0, 1.0, 1.0, 1.0],
26        }
27    }
28}
29
30/// An indiced [`Mesh`], stored along with it's vertex array, index array and vertex buffer.
31#[derive(Debug)]
32pub struct Mesh {
33    /// Vertices of the Mesh.
34    ///
35    /// Represented as a [`Vec`] of [`Vertex`]s.
36    pub vertices: Vec<Vertex>,
37    /// Indices of the Mesh.
38    ///
39    /// Stored as a [`Vec`] of [`u32`].
40    pub indices: Vec<u32>,
41    vao: WebGlVertexArrayObject,
42    vbo: WebGlBuffer,
43    ibo: WebGlBuffer,
44}
45
46impl Drop for Mesh {
47    fn drop(&mut self) {
48        use gl::Bind;
49        let gl = gl::get_context();
50        self.unbind(&gl);
51
52        gl.delete_buffer(Some(&self.vbo));
53        gl.delete_buffer(Some(&self.ibo));
54        self.vertices.clear();
55        self.indices.clear();
56        gl.delete_vertex_array(Some(&self.vao));
57    }
58}
59
60impl gl::Bind for Mesh {
61    /// Bind the `WebGlVertexArrayObject` of the `Mesh`.
62    fn bind(&self, gl: &GL) {
63        gl.bind_vertex_array(Some(&self.vao));
64    }
65    fn unbind(&self, gl: &GL) {
66        gl.bind_vertex_array(None);
67    }
68}
69
70impl Mesh {
71    /// Create a new [`Mesh`] with the given [`vertices`](Vertex) and indices.
72    pub fn new(gl: &GL, vertices: Vec<Vertex>, indices: Vec<u32>) -> Self {
73        Self {
74            vertices,
75            indices,
76            vao: {
77                let vao = gl
78                    .create_vertex_array()
79                    .expect("Could not create Vertex Array Object.");
80                gl.bind_vertex_array(Some(&vao));
81                vao
82            },
83            vbo: gl.create_buffer().expect("Could not create Buffer."),
84            ibo: gl.create_buffer().expect("Could not create Buffer."),
85        }
86    }
87    /// Create a new Quad mesh with a side length of 1m
88    pub fn quad(gl: &GL) -> Self {
89        Self::quad_with_side(gl, 1.0)
90    }
91    /// Create a new Quad mesh with a given side length
92    pub fn quad_with_side(gl: &GL, side: f32) -> Self {
93        let half = side / 2.0;
94        let vertices = vec![
95            Vertex {
96                position: [-half, half],
97                uv: [0.0, 0.0],
98                ..Default::default()
99            },
100            Vertex {
101                position: [-half, -half],
102                uv: [0.0, 1.0],
103                ..Default::default()
104            },
105            Vertex {
106                position: [half, -half],
107                uv: [1.0, 1.0],
108                ..Default::default()
109            },
110            Vertex {
111                position: [half, half],
112                uv: [1.0, 0.0],
113                ..Default::default()
114            },
115        ];
116        let indices: Vec<u32> = vec![0, 2, 1, 0, 3, 2];
117        Self::new(gl, vertices, indices)
118    }
119
120    /// Set up the vertex (vbo) and index (ibo) `WebGlBuffer` and send their data to the GPU.
121    pub fn setup(&self, gl: &GL) {
122        use gl::Bind;
123        self.bind(gl);
124
125        gl.bind_buffer(GL::ARRAY_BUFFER, Some(&self.vbo));
126        gl.bind_buffer(GL::ELEMENT_ARRAY_BUFFER, Some(&self.ibo));
127
128        let vertex_slice = unsafe {
129            std::slice::from_raw_parts(
130                self.vertices.as_ptr() as *const u8,
131                self.vertices.len() * std::mem::size_of::<Vertex>(),
132            )
133        };
134        let index_slice = unsafe {
135            std::slice::from_raw_parts(
136                self.indices.as_ptr() as *const u8,
137                self.indices.len() * std::mem::size_of::<u32>(),
138            )
139        };
140
141        gl.buffer_data_with_u8_array(GL::ARRAY_BUFFER, vertex_slice, GL::DYNAMIC_DRAW);
142        gl.buffer_data_with_u8_array(GL::ELEMENT_ARRAY_BUFFER, index_slice, GL::DYNAMIC_DRAW);
143
144        gl.vertex_attrib_pointer_with_i32(0, 2, GL::FLOAT, false, 8 * 4, 0);
145        gl.vertex_attrib_pointer_with_i32(1, 2, GL::FLOAT, false, 8 * 4, 8);
146        gl.vertex_attrib_pointer_with_i32(2, 4, GL::FLOAT, false, 8 * 4, 16);
147
148        gl.enable_vertex_attrib_array(0);
149        gl.enable_vertex_attrib_array(1);
150        gl.enable_vertex_attrib_array(2);
151    }
152}