easy_opengl/
buffers.rs

1use std::ffi::c_void;
2
3#[derive(Clone, Copy)]
4pub enum VertexAttribType {
5    Float,
6    Float2,
7    Float3,
8    Float4,
9    Mat3,
10    Mat4,
11    Int,
12    Int2,
13    Int3,
14    Int4,
15    Uint,
16    Byte,
17}
18
19pub fn vertex_attrib_type_gl(vtype: &VertexAttribType) -> u32 {
20    match vtype {
21        VertexAttribType::Float => gl::FLOAT,
22        VertexAttribType::Float2 => gl::FLOAT,
23        VertexAttribType::Float3 => gl::FLOAT,
24        VertexAttribType::Float4 => gl::FLOAT,
25        VertexAttribType::Mat3 => gl::FLOAT,
26        VertexAttribType::Mat4 => gl::FLOAT,
27        VertexAttribType::Int => gl::INT,
28        VertexAttribType::Int2 => gl::INT,
29        VertexAttribType::Int3 => gl::INT,
30        VertexAttribType::Int4 => gl::INT,
31        VertexAttribType::Uint => gl::UNSIGNED_INT,
32        VertexAttribType::Byte => gl::BYTE,
33    }
34}
35
36pub fn vertex_attrib_type_size(vtype: &VertexAttribType) -> u32 {
37    match vtype {
38        VertexAttribType::Float => 4,
39        VertexAttribType::Float2 => 4 * 2,
40        VertexAttribType::Float3 => 4 * 3,
41        VertexAttribType::Float4 => 4 * 4,
42        VertexAttribType::Mat3 => 4 * 3 * 3,
43        VertexAttribType::Mat4 => 4 * 4 * 4,
44        VertexAttribType::Int => 4,
45        VertexAttribType::Int2 => 4 * 2,
46        VertexAttribType::Int3 => 4 * 3,
47        VertexAttribType::Int4 => 4 * 4,
48        VertexAttribType::Uint => 4,
49        VertexAttribType::Byte => 1,
50    }
51}
52
53pub fn vertex_attrib_type_count(vtype: &VertexAttribType) -> u32 {
54    match vtype {
55        VertexAttribType::Float => 1,
56        VertexAttribType::Float2 => 2,
57        VertexAttribType::Float3 => 3,
58        VertexAttribType::Float4 => 4,
59        VertexAttribType::Mat3 => 3 * 3,
60        VertexAttribType::Mat4 => 4 * 4,
61        VertexAttribType::Int => 1,
62        VertexAttribType::Int2 => 2,
63        VertexAttribType::Int3 => 3,
64        VertexAttribType::Int4 => 4,
65        VertexAttribType::Uint => 1,
66        VertexAttribType::Byte => 1,
67    }
68}
69
70/// A abstract representation of a vertex attribute
71///
72/// # Example
73///
74/// ``` Rust
75/// let attrib = VertexAttrib::new(
76///       VertexAttribType::Float3, // We want to send a vector3
77///       false, // normalize
78///       "pos".to_string(), // the name is only to know the which attribute is to the end user
79/// )
80/// ```
81pub struct VertexAttrib {
82    pub size: u32,
83    pub offset: u32,
84    pub vtype: VertexAttribType,
85    pub normalize: bool,
86    pub name: String,
87}
88
89impl VertexAttrib {
90    pub fn new(vtype: VertexAttribType, normalize: bool, name: String) -> Self {
91        Self {
92            size: vertex_attrib_type_size(&vtype),
93            offset: 0,
94            vtype,
95            normalize,
96            name,
97        }
98    }
99}
100
101/// Attach the vector of vertex attributes to a binded vertex array
102///
103/// # Example
104/// ``` Rust
105///    let vertices = vec![
106///        0.5, 0.5, 0.0, // top right
107///        0.5, -0.5, 0.0, // bottom right
108///        -0.5, -0.5, 0.0, // bottom left
109///        -0.5, 0.5, 0.0, // top left
110///    ];
111///    let vao = VertexArray::new();
112///    vao.bind();
113///    submit_vertex_attribs(&mut vec![VertexAttrib::new(
114///        VertexAttribType::Float3,
115///        false,
116///        "pos".to_string(),
117///    )]);
118/// ```
119pub fn submit_vertex_attribs(vertex_attribs: &mut Vec<VertexAttrib>) {
120    let mut stride = 0;
121    let mut offset = 0;
122    for attrib in vertex_attribs.iter_mut() {
123        attrib.offset += offset;
124        offset += attrib.size;
125        stride += attrib.size;
126    }
127
128    let mut i = 0;
129    for attrib in vertex_attribs {
130        if vertex_attrib_type_gl(&attrib.vtype) == gl::FLOAT {
131            unsafe {
132                gl::VertexAttribPointer(
133                    i,
134                    vertex_attrib_type_count(&attrib.vtype) as i32,
135                    vertex_attrib_type_gl(&attrib.vtype),
136                    attrib.normalize as u8,
137                    stride as i32,
138                    attrib.offset as *const std::ffi::c_void,
139                );
140            }
141        } else {
142            unsafe {
143                gl::VertexAttribIPointer(
144                    i,
145                    vertex_attrib_type_count(&attrib.vtype) as i32,
146                    vertex_attrib_type_gl(&attrib.vtype),
147                    stride as i32,
148                    attrib.offset as *const std::ffi::c_void,
149                );
150            }
151        }
152
153        unsafe {
154            gl::EnableVertexAttribArray(i);
155        }
156
157        i += 1;
158    }
159}
160
161fn gen_vao() -> u32 {
162    let mut vao: u32 = 0;
163    unsafe { gl::GenVertexArrays(1, &mut vao) }
164    vao
165}
166
167fn gen_buffer() -> u32 {
168    let mut buffer: u32 = 0;
169    unsafe { gl::GenBuffers(1, &mut buffer) }
170    buffer
171}
172
173pub fn calc_bytes_size<T>(v: &Vec<T>) -> usize {
174    v.len() * std::mem::size_of::<T>()
175}
176
177/// A abstract representation of a vertex array
178/// # Example
179/// ``` Rust
180///    let vertices = vec![
181///        0.5, 0.5, 0.0, // top right
182///        0.5, -0.5, 0.0, // bottom right
183///        -0.5, -0.5, 0.0, // bottom left
184///        -0.5, 0.5, 0.0, // top left
185///    ];
186///    let indices = vec![
187///        0, 1, 3, // first Triangle
188///        1, 2, 3, // second Triangle
189///    ];
190///
191///    let vao = VertexArray::new();
192///    let _vbo = VertexBuffer::new(calc_bytes_size(&vertices) as isize, Some(&vertices));
193///
194///    vao.bind();
195///
196///    submit_vertex_attribs(&mut vec![VertexAttrib::new(
197///        VertexAttribType::Float3,
198///        false,
199///        "pos".to_string(),
200///    )]);
201///
202///    let _ibo = IndexBuffer::new(calc_bytes_size(&indices) as isize, Some(&indices));
203/// ```
204pub struct VertexArray {
205    pub id: u32,
206}
207
208impl VertexArray {
209    /// Return a vertext array
210
211    pub fn new() -> Self {
212        Self { id: gen_vao() }
213    }
214
215    pub fn bind(&self) {
216        unsafe {
217            gl::BindVertexArray(self.id);
218        }
219    }
220
221    pub fn unbind(&self) {
222        unsafe {
223            gl::BindVertexArray(0);
224        }
225    }
226}
227
228/// A abstract representation of a vertex buffer
229///  # Example
230/// ``` Rust
231///    let vertices = vec![
232///        0.5, 0.5, 0.0, // top right
233///        0.5, -0.5, 0.0, // bottom right
234///        -0.5, -0.5, 0.0, // bottom left
235///        -0.5, 0.5, 0.0, // top left
236///    ];
237///
238///    // static
239///    let vbo1 = VertexBuffer::new(calc_bytes_size(&vertices) as isize, Some(&vertices));
240///
241///    // Dynamic
242///    let vbo2 = VertexBuffer::new(calc_bytes_size(&vertices) as isize);
243///
244///    // send half of the vertices
245///    vbo2.send_data(48 / 2, 0, vertices);
246/// ```
247pub struct VertexBuffer {
248    pub id: u32,
249}
250
251impl VertexBuffer {
252    /// Return a VertexBuffer with the allocated size provided, the buffer data is static only if
253    /// the verticies isn't None, else, the buffer data is dynamic
254    ///
255    ///  # Arguments
256    ///  * `size` - The size in bytes of the data to allocate
257    ///  * `vertices` - A optional data to write
258    pub fn new<T>(size: isize, vertices: Option<&Vec<T>>) -> Self {
259        let _self = Self { id: gen_buffer() };
260        _self.bind();
261
262        if let Some(vertices) = vertices {
263            unsafe {
264                gl::BufferData(
265                    gl::ARRAY_BUFFER,
266                    size,
267                    vertices.as_ptr() as *const std::ffi::c_void,
268                    gl::STATIC_DRAW,
269                );
270            }
271        } else {
272            unsafe {
273                gl::BufferData(gl::ARRAY_BUFFER, size, std::ptr::null(), gl::DYNAMIC_DRAW);
274            }
275        }
276
277        _self
278    }
279
280    /// Write data that wasn't provided on the new function
281    ///
282    ///  # Arguments
283    ///  * `size` - The size in bytes of the data to write
284    ///  * `offset` - Point to a offset in the allocated space
285    ///  * `vertices` - Data to write
286    pub fn send_data<T>(&self, size: isize, offset: isize, vertices: &Vec<T>) {
287        unsafe {
288            self.bind();
289            gl::BufferSubData(
290                gl::ARRAY_BUFFER,
291                offset,
292                size,
293                vertices.as_ptr() as *const std::ffi::c_void,
294            );
295        }
296    }
297
298    pub fn bind(&self) {
299        unsafe {
300            gl::BindBuffer(gl::ARRAY_BUFFER, self.id);
301        }
302    }
303
304    pub fn unbind(&self) {
305        unsafe {
306            gl::BindBuffer(gl::ARRAY_BUFFER, 0);
307        }
308    }
309}
310
311/// A abstract representation of a index buffer
312///  # Example
313/// ``` Rust
314///    let indices = vec![
315///        0, 1, 3, // first Triangle
316///        1, 2, 3, // second Triangle
317///    ];
318///
319///    // static
320///    let ibo1 = VertexBuffer::new(calc_bytes_size(&indices) as isize, Some(&vertices));
321///
322///    // Dynamic
323///    let ibo2 = VertexBuffer::new(calc_bytes_size(&indices) as isize);
324///
325///    // send half of the vertices
326///    ibo2.send_data(24 / 2, 0, &indices);
327/// ```
328pub struct IndexBuffer {
329    pub id: u32,
330}
331
332impl IndexBuffer {
333    /// Return a IndexBuffer with the allocated size provided, the buffer data is static only if
334    /// the indices isn't None, else, the buffer data is dynamic
335    ///
336    ///  # Arguments
337    ///  * `size` - The size in bytes of the data to allocate
338    ///  * `indices` - A optional data to write
339    pub fn new(size: isize, indices: Option<&Vec<i32>>) -> Self {
340        let _self = Self { id: gen_buffer() };
341        _self.bind();
342
343        if let Some(indices) = indices {
344            unsafe {
345                gl::BufferData(
346                    gl::ELEMENT_ARRAY_BUFFER,
347                    size,
348                    indices.as_ptr() as *const std::ffi::c_void,
349                    gl::STATIC_DRAW,
350                );
351            }
352        } else {
353            unsafe {
354                gl::BufferData(
355                    gl::ELEMENT_ARRAY_BUFFER,
356                    size,
357                    std::ptr::null(),
358                    gl::DYNAMIC_DRAW,
359                );
360            }
361        }
362        _self
363    }
364
365    /// Write data that wasn't provided on the new function
366    ///
367    ///  # Arguments
368    ///  * `size` - The size in bytes of the data to write
369    ///  * `offset` - Point to a offset in the allocated space
370    ///  * `indices` - Data to write
371    pub fn send_data(&self, size: isize, offset: isize, indices: &Vec<i32>) {
372        unsafe {
373            self.bind();
374            gl::BufferSubData(
375                gl::ELEMENT_ARRAY_BUFFER,
376                offset,
377                size,
378                indices.as_ptr() as *const std::ffi::c_void,
379            );
380        }
381    }
382
383    pub fn bind(&self) {
384        unsafe {
385            gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, self.id);
386        }
387    }
388
389    pub fn unbind(&self) {
390        unsafe {
391            gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, 0);
392        }
393    }
394}
395
396/// A abstract representation of a dynamic uniform buffer
397pub struct UniforBuffer {
398    pub id: u32,
399    pub slot: u32,
400}
401
402impl UniforBuffer {
403    /// # Arguments
404    /// * `size` - Size in bytes of the buffer
405    /// * `binding` - The binding slot
406    pub fn new(size: isize, binding: u32) -> Self {
407        let _self = Self {
408            id: gen_buffer(),
409            slot: binding,
410        };
411        unsafe {
412            gl::BufferData(gl::UNIFORM_BUFFER, size, std::ptr::null(), gl::DYNAMIC_DRAW);
413            gl::BindBufferBase(gl::UNIFORM_BUFFER, _self.slot, _self.id);
414        }
415
416        _self
417    }
418
419    /// # Arguments
420    /// * `data` - A void ptr to a array of data
421    /// * `size` - Size in bytes of the buffer
422    /// * `offset` - Offset pointing on the allocated data
423    pub fn send_data(&self, data: *const c_void, size: isize, offset: isize) {
424        unsafe {
425            gl::BindBufferBase(gl::UNIFORM_BUFFER, self.slot, self.id);
426            gl::BufferSubData(gl::UNIFORM_BUFFER, offset, size, data);
427        }
428    }
429}
430
431impl Drop for VertexArray {
432    fn drop(&mut self) {
433        unsafe { gl::DeleteVertexArrays(1, &self.id) }
434    }
435}
436
437impl Drop for VertexBuffer {
438    fn drop(&mut self) {
439        unsafe { gl::DeleteBuffers(1, &self.id) }
440    }
441}
442
443impl Drop for IndexBuffer {
444    fn drop(&mut self) {
445        unsafe { gl::DeleteBuffers(1, &self.id) }
446    }
447}
448
449impl Drop for UniforBuffer {
450    fn drop(&mut self) {
451        unsafe { gl::DeleteBuffers(1, &self.id) }
452    }
453}