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
use std::{ffi::c_void, mem::{offset_of, size_of}, ptr};

use super::{Renderer, Shader, Vertex, DEFAULT_MESH_SHADER_FS, DEFAULT_MESH_SHADER_VS};

use gl::*;

#[derive(PartialEq, Debug)]
pub struct Mesh {
    vertices: Vec<Vertex>,
    indices: Vec<u32>,

    pub VAO: u32,
    EBO: u32,
    VBO: u32,

    shader: Shader,
}

impl Mesh {
    pub fn new(vertices: Vec<Vertex>, indices: Vec<u32>) -> Self {
        let shader = Shader::new_pipeline(DEFAULT_MESH_SHADER_VS, DEFAULT_MESH_SHADER_FS);
        let mut mesh = Mesh {
            vertices, indices,
            VAO: 0, VBO: 0, EBO: 0,
            shader,
        };

        unsafe { mesh.setup_mesh() }

        mesh
    }

    pub unsafe fn setup_mesh(&mut self) {
        GenVertexArrays(1, &mut self.VAO);
        GenBuffers(1, &mut self.VBO);
        GenBuffers(1, &mut self.EBO);

        BindVertexArray(self.VAO);

        BindBuffer(ARRAY_BUFFER, self.VBO);

        let size = (self.vertices.len() * size_of::<Vertex>()) as isize;
        let data = &self.vertices[0] as *const Vertex as *const c_void;
        BufferData(ARRAY_BUFFER, size, data, STATIC_DRAW);

        BindBuffer(ELEMENT_ARRAY_BUFFER, self.EBO);
        let size = (self.indices.len() * size_of::<u32>()) as isize;
        let data = &self.indices[0] as *const u32 as *const c_void;
        BufferData(ELEMENT_ARRAY_BUFFER, size, data, STATIC_DRAW);

        let size = size_of::<Vertex>() as i32;

        EnableVertexAttribArray(0);
        VertexAttribPointer(0, 3, FLOAT, FALSE, size, offset_of!(Vertex, position) as *const c_void);
        // EnableVertexAttribArray(1);
        // VertexAttribPointer(1, 3, FLOAT, FALSE, size, offset_of!(Vertex, color) as *const c_void);

        BindVertexArray(0);
    }
    
    pub unsafe fn draw(&self) {
        BindVertexArray(self.VAO);
        self.shader.use_shader();
        DrawElements(TRIANGLES, self.indices.len() as i32, UNSIGNED_INT, ptr::null());
        BindVertexArray(0);
        UseProgram(0);
    }
}

impl Renderer {
    pub fn add_mesh(&mut self, name: &str, vertices: Vec<Vertex>, indices: Vec<u32>) {
        // before adding a mesh with certain name, 
        // assure it has not been already added
        if self.meshes.get(name).is_some() { return };

        let mesh = Mesh::new(vertices, indices);
        self.meshes.insert(name.to_owned(), mesh);
    }

    pub fn get_mesh(&mut self, name: &str) -> Option<&mut Mesh> {
        self.meshes.get_mut(name)
    }
}