fere_resources/
mesh.rs

1pub mod obj;
2
3use fere_common::*;
4use gl::types::*;
5
6#[derive(Debug, Default)]
7pub struct MeshData {
8    pub name: String,
9
10    pub pos: Vec<Vec3>,
11    pub normal: Vec<Vec3>,
12    pub uv: Vec<Vec2>,
13    pub tan: Vec<Vec3>,
14
15    pub minmax: Option<(Vec3, Vec3)>,
16}
17
18impl MeshData {
19    pub fn merge(meshes: Vec<MeshData>) -> Self {
20        let init = MeshData {
21            name: "".to_owned(),
22            pos: Vec::new(),
23            normal: Vec::new(),
24            uv: Vec::new(),
25            tan: Vec::new(),
26            minmax: None,
27        };
28        meshes.into_iter().fold(init, |mut acc, mut x| {
29            acc.name += &x.name;
30            acc.pos.append(&mut x.pos);
31            acc.normal.append(&mut x.normal);
32            acc.uv.append(&mut x.uv);
33            acc.tan.append(&mut x.tan);
34            acc
35        })
36    }
37
38    pub fn create_description(&self) -> MeshDescription {
39        let mean_pos = self.pos.iter().sum::<Vec3>() / self.pos.len() as f32;
40        MeshDescription { mean_pos }
41    }
42}
43
44#[derive(Debug)]
45pub struct MeshDescription {
46    pub mean_pos: Vec3,
47}
48
49#[derive(Debug)]
50pub struct Mesh {
51    pub name: String,
52    // If it's not from the particular file, then None
53    pub path: Option<String>,
54    pub size: usize,
55
56    // CPU things - will be purged from memory after buffer
57    data: Option<MeshData>,
58    description: MeshDescription,
59
60    // GPU things - will exist only after buffer
61    vao: GLuint,
62    vbo: GLuint,
63}
64
65impl Mesh {
66    pub fn new(path: Option<String>, data: MeshData) -> Self {
67        let description = data.create_description();
68        Mesh {
69            name: data.name.clone(),
70            path,
71            size: data.pos.len(),
72            data: Some(data),
73            vao: 0,
74            vbo: 0,
75            description,
76        }
77    }
78
79    pub fn description(&self) -> &MeshDescription {
80        &self.description
81    }
82
83    pub fn buffer(&mut self) {
84        unsafe {
85            gl::GenVertexArrays(1, &mut self.vao);
86            gl::BindVertexArray(self.vao);
87            gl::GenBuffers(1, &mut self.vbo);
88            gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo);
89
90            self.size = self.data.as_ref().unwrap().pos.len();
91            if self.size == 0 {
92                return;
93            }
94
95            let data = self.data.take().unwrap();
96            let f = 4; // size of f32
97            let n = self.size as isize;
98
99            gl::BufferData(
100                gl::ARRAY_BUFFER,
101                f * (n * 3 + n * 3 + n * 2 + n * 3),
102                std::ptr::null(),
103                gl::STATIC_DRAW,
104            );
105            gl::BufferSubData(
106                gl::ARRAY_BUFFER,
107                0,
108                f * (n * 3),
109                data.pos[0].as_ptr().cast(),
110            );
111            gl::BufferSubData(
112                gl::ARRAY_BUFFER,
113                f * (n * 3),
114                f * (n * 3),
115                data.normal[0].as_ptr().cast(),
116            );
117
118            if !data.uv.is_empty() {
119                gl::BufferSubData(
120                    gl::ARRAY_BUFFER,
121                    f * (n * 6),
122                    f * (n * 2),
123                    data.uv[0].as_ptr().cast(),
124                );
125            }
126            if !data.tan.is_empty() {
127                gl::BufferSubData(
128                    gl::ARRAY_BUFFER,
129                    f * (n * 8),
130                    f * (n * 3),
131                    data.tan[0].as_ptr().cast(),
132                );
133            }
134
135            gl::EnableVertexAttribArray(0);
136            gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE, 0, std::ptr::null::<u8>().cast());
137            gl::EnableVertexAttribArray(1);
138            gl::VertexAttribPointer(
139                1,
140                3,
141                gl::FLOAT,
142                gl::FALSE,
143                0,
144                ((f * 3 * n) as *const u8).cast(),
145            );
146            if !data.uv.is_empty() {
147                gl::EnableVertexAttribArray(2);
148                gl::VertexAttribPointer(
149                    2,
150                    2,
151                    gl::FLOAT,
152                    gl::FALSE,
153                    0,
154                    ((f * 6 * n) as *const u8).cast(),
155                );
156            }
157            if !data.tan.is_empty() {
158                gl::EnableVertexAttribArray(3);
159                gl::VertexAttribPointer(
160                    3,
161                    3,
162                    gl::FLOAT,
163                    gl::FALSE,
164                    0,
165                    ((f * 8 * n) as *const u8).cast(),
166                );
167            }
168        }
169    }
170
171    pub fn bind(&self) {
172        debug_assert!(self.data.is_none(), "bind() on an unbufferd mesh");
173        unsafe { gl::BindVertexArray(self.vao) }
174    }
175
176    pub fn bind_or_buffer(&mut self) {
177        if self.data.is_some() {
178            self.buffer();
179        }
180        unsafe { gl::BindVertexArray(self.vao) }
181    }
182
183    pub fn draw(&self) {
184        unsafe { gl::DrawArrays(gl::TRIANGLES, 0, self.size as i32) }
185    }
186
187    /// Treat this mesh as a line
188    pub fn draw_line(&self) {
189        unsafe { gl::DrawArrays(gl::LINES, 0, 2) }
190    }
191
192    pub fn draw_wireframe(&self) {
193        unsafe {
194            gl::Disable(gl::CULL_FACE);
195            gl::PolygonMode(gl::FRONT_AND_BACK, gl::LINE);
196            gl::DrawArrays(gl::TRIANGLES, 0, self.size as i32);
197            gl::PolygonMode(gl::FRONT_AND_BACK, gl::FILL);
198            gl::Enable(gl::CULL_FACE);
199        }
200    }
201}
202
203impl Drop for Mesh {
204    fn drop(&mut self) {
205        if self.data.is_none() {
206            unsafe {
207                gl::DeleteVertexArrays(1, &self.vao);
208                gl::DeleteBuffers(1, &self.vbo);
209            }
210        }
211    }
212}