dzahui/simulation/drawable/binder.rs
1// Internal dependencies
2use crate::Error;
3
4// External dependencies
5use gl::{ self, types::{GLfloat, GLsizei, GLsizeiptr, GLuint}};
6use std::{mem, os::raw::c_void, ptr};
7use ndarray::Array1;
8
9
10/// # General Information
11///
12/// An object that can be represented in CPU via a, ebo, vbo, vao and texture (the latter is not necessary).
13///
14pub(crate) trait Bindable {
15 /// Obtains binder associated to object. Getter.
16 fn get_binder(&self) -> Result<&Binder, Error>;
17
18 /// Obtain binder mutable reference.
19 fn get_mut_binder(&mut self) -> Result<&mut Binder, Error>;
20
21 /// Shortcut to binder setup function.
22 fn setup(&mut self) -> Result<(), Error> {
23 Ok(self.get_mut_binder()?.setup())
24 }
25
26 /// Shortcut to setup texture function.
27 fn setup_texture(&mut self) -> Result<(), Error> {
28 Ok(self.get_mut_binder()?.setup_texture())
29 }
30
31 /// Shortcut to bind all without texture function.
32 fn bind_all_no_texture(&self) -> Result<(), Error> {
33 Ok(self.get_binder()?.bind_all_no_texture())
34 }
35
36 /// Shortcut to bind all function.
37 fn bind_all(&self) -> Result<(), Error> {
38 Ok(self.get_binder()?.bind_all())
39 }
40
41 /// Shortcut to bind vao function
42 fn bind_vao(&self) -> Result<(), Error> {
43 Ok(self.get_binder()?.bind_vao())
44 }
45
46 /// Shortcut to bind texture
47 fn bind_texture(&self) -> Result<(), Error> {
48 Ok(self.get_binder()?.bind_texture())
49 }
50
51 /// Shortcut to unbind texture
52 fn unbind_texture(&self) -> Result<(), Error> {
53 Ok(self.get_binder()?.unbind_texture())
54 }
55}
56
57/// # General Information
58///
59/// All objects that can be drawn by OpenGL should implement a drawable trait. The main functions are
60/// setup and draw. Both which contain general implementations to setup drawable object in GPU and draw it respectively.
61///
62pub(crate) trait Drawable: Bindable {
63 /// Creates a way to obtain vertices from drawable object. Getter.
64 fn get_vertices(&self) -> Result<Array1<f32>, Error>;
65 /// Creates a way to obtain indices to draw vertices (and triangles). Getter.
66 fn get_indices(&self) -> Result<&Array1<u32>, Error>;
67 /// Creates a way to obtain order of object's dimensions. Getter.
68 fn get_max_length(&self) -> Result<f32, Error>;
69
70 /// # General Information
71 ///
72 /// Once an object with Drawable trait has been created it can be sent to gpu.
73 /// This function will send vertex and indices information to GPU to be drawn on screen.
74 /// There's a couple of steps that should never be skipped:
75 ///
76 /// - Object's binder has to have been initialized prior to this function call.
77 /// - Always bind object's binder's vao and/or texture.
78 /// - There's no need to bind ebo or vbo once vao is bound.
79 ///
80 /// # Parameters
81 ///
82 /// * `&self` - All information is stored inside the object an accesed through the getter methods above.
83 ///
84 fn send_to_gpu(&self) -> Result<(), Error> {
85 let vertices = self.get_vertices()?;
86 let indices = self.get_indices()?;
87
88 unsafe {
89 // Point to data, specify data length and how it should be drawn (static draw serves to only draw once).
90 gl::BufferData(
91 gl::ARRAY_BUFFER,
92 (vertices.len() * mem::size_of::<GLfloat>()) as GLsizeiptr,
93 &vertices[0] as *const f32 as *const c_void,
94 // Double casting to raw pointer. Equivalent to C's void type when used as pointer.
95 gl::DYNAMIC_DRAW,
96 );
97
98 // Point to data, specify data length and how it should be drawn
99 gl::BufferData(
100 gl::ELEMENT_ARRAY_BUFFER,
101 (indices.len() * mem::size_of::<GLuint>()) as GLsizeiptr,
102 &indices[0] as *const u32 as *const c_void,
103 gl::DYNAMIC_DRAW,
104 );
105
106 // How should coordinates be read.
107 // Reading starts at index 0.
108 // Each coordinate is composed of 3 values.
109 // No normalized coordinates.
110 // The next coordinate is located 3 values after the first index of the previous one.
111 // The offset to start reading coordinates (for position it's normally zero. It is used when having texture and/or color coordinates).
112 gl::VertexAttribPointer(
113 0,
114 3,
115 gl::FLOAT,
116 gl::FALSE,
117 (6 * mem::size_of::<GLfloat>()) as GLsizei,
118 ptr::null(),
119 );
120 // Enable vertex atributes giving vertex location (setup in vertex shader).
121 gl::EnableVertexAttribArray(0);
122
123 // Enable color visibility
124 gl::VertexAttribPointer(
125 1,
126 3,
127 gl::FLOAT,
128 gl::FALSE,
129 (6 * mem::size_of::<GLfloat>()) as GLsizei,
130 (3 * mem::size_of::<GLfloat>()) as *const c_void,
131 );
132 gl::EnableVertexAttribArray(1);
133 }
134 Ok(())
135 }
136
137 /// # General Information
138 ///
139 /// A simple call to glDrawElements in triangles mode. It assumes all information to be drawn has been sent and is stored in a single vbo, veo pair.
140 /// (Making multiple calls to draw is, in general, not a good idea, since it can really slow down a program reducing the FPS. When drawing
141 /// multiple objects, it's better to use the so called 'batch rendering').
142 ///
143 /// # Parameters
144 ///
145 /// * `&self` - A reference to the object which is attached to a binder and knows how to get the indices and indices length.
146 ///
147 fn draw(&self) -> Result<(), Error> {
148 let indices_len: i32 = self.get_indices()?.len() as i32;
149
150 // Draw only when window is created and inside loop
151 // Drawn as triangles
152 unsafe {
153 // Draw
154 // Comment to see the triangles filled instead of only the lines that form them.
155 gl::DrawElements(gl::TRIANGLES, indices_len, gl::UNSIGNED_INT, ptr::null());
156 }
157
158 Ok(())
159 }
160}
161
162/// # General Information
163///
164/// Variables asocciated with GPU and drawable object(s). Assigned by OpenGL. Should always be mutable.
165///
166/// # Fields
167///
168/// * `vbo` (Vertex Buffer Object) - Vertices Generated by Mesh.
169/// * `vao` (Vertex Array Object) - Binds vertices and it's configuration with OpenGL.
170/// * `ebo` (Element Buffer Object) - Indices to draw vertices.
171/// * `texture` - Texture in 2D to use over object to draw.
172///
173#[derive(Debug, PartialEq, Eq)]
174pub(crate) struct Binder {
175 pub(crate) vbo: u32,
176 pub(crate) vao: u32,
177 pub(crate) ebo: u32,
178 pub(crate) texture: u32,
179}
180
181impl Binder {
182 /// Simple new function. Generates new instance of Binder.
183 pub(crate) fn new() -> Binder {
184 Binder {
185 vbo: 0,
186 vao: 0,
187 ebo: 0,
188 texture: 0,
189 }
190 }
191
192 /// # General Information
193 ///
194 /// sets up binder's variables with GPU. Should always be used after instance of window has set up OpenGL context. Never binds texture.
195 ///
196 /// # Parameters
197 ///
198 /// * `&mut self` - OpenGL changes the values of instance fields effectively setting up linkage beetween vao and vbo and ebo. Texture has to be set up later since not
199 /// all drawings have it.
200 ///
201 pub(crate) fn setup(&mut self) {
202 unsafe {
203 // Create VAO
204 gl::GenVertexArrays(1, &mut self.vao);
205 // Bind Vertex Array Object first
206 // Since it is bound first, it binds to the EBO and VBO (because they are the only ones being bound after it)
207 gl::BindVertexArray(self.vao);
208
209 // Generates a VBO in GPU
210 gl::GenBuffers(1, &mut self.vbo);
211 // Generates a EBO in GPU
212 gl::GenBuffers(1, &mut self.ebo);
213 // Bind VBO
214 gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo);
215 // BInd VAO
216 gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, self.ebo);
217 }
218 }
219
220 /// # General Information
221 ///
222 /// Binds binder's vao to use.
223 ///
224 /// # Parameters
225 ///
226 /// * `&self` - Instance does not need to be mutable since it's already setup.
227 ///
228 pub(crate) fn bind_vao(&self) {
229 unsafe {
230 gl::BindVertexArray(self.vao);
231 }
232 }
233
234 /// # General Information
235 ///
236 /// Binds binder's vbo to use.
237 ///
238 /// # Parameters
239 ///
240 /// * `&self` - Instance does not need to be mutable since it's already setup.
241 ///
242 pub(crate) fn bind_vbo(&self) {
243 unsafe {
244 gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo);
245 }
246 }
247
248 /// # General Information
249 ///
250 /// Binds binder's ebo to use.
251 ///
252 /// # Parameters
253 ///
254 /// * `&self` - Instance does not need to be mutable since it's already setup.
255 ///
256 pub(crate) fn bind_ebo(&self) {
257 unsafe {
258 gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, self.ebo);
259 }
260 }
261
262 /// # General Information
263 ///
264 /// Binds vao, ebo and vbo. Never binds texture.
265 ///
266 /// # Parameters
267 ///
268 /// * `&self` - Instance does not need to be mutable since it's already setup.
269 ///
270 #[allow(dead_code)]
271 pub(crate) fn bind_all_no_texture(&self) {
272 self.bind_vao();
273 self.bind_vbo();
274 self.bind_ebo();
275 }
276
277 /// # General Information
278 ///
279 /// Binds a 2D texture providing a standar way to scale up and down (mipmap), and enabling blending so that alpha channel is respected.
280 /// When enabling blending, it's necessary to change how it occurs: If alpha channel is to be respected, the incoming pixels have to be alpha transparent,
281 /// while the pixes already present have to be (1-alpha) transparent.
282 ///
283 /// # Parameters
284 ///
285 /// * `&mut self` - OpenGL changes values of instance field texture effectively linking current texture to use.
286 ///
287 pub(crate) fn setup_texture(&mut self) {
288 unsafe {
289 // generate and bind texture
290 gl::GenTextures(1, &mut self.texture);
291 gl::BindTexture(gl::TEXTURE_2D, self.texture);
292 }
293 }
294
295 /// # General Information
296 ///
297 /// Binds binder's texture to use.
298 ///
299 /// # Parameters
300 ///
301 /// * `&self` - Instance does not need to be mutable since it's already setup.
302 ///
303 pub(crate) fn bind_texture(&self) {
304 unsafe {
305 gl::BindTexture(gl::TEXTURE_2D, self.texture);
306 }
307 }
308
309 /// # General information
310 ///
311 /// Unbind texture when needed. Since not all objects posess a texture, this has to be done sometimes.
312 ///
313 pub(crate) fn unbind_texture(&self) {
314 unsafe {
315 gl::BindTexture(gl::TEXTURE_2D, 0);
316 }
317 }
318
319 /// # General Information
320 ///
321 /// Binds vao, ebo, vbo and texture.
322 ///
323 /// # Parameters
324 ///
325 /// * `&self` - Instance does not need to be mutable since it's already setup.
326 ///
327 pub(crate) fn bind_all(&self) {
328 self.bind_vao();
329 self.bind_vbo();
330 self.bind_ebo();
331 self.bind_texture();
332 }
333}