Skip to main content

gust_render/
vertex_buffer.rs

1//! This module encapsulate the system of vertexBuffer
2//! Here you can create a drawable object easily with a VertexArray
3
4use draw::{BlendMode, Context, Drawable, DrawableMut, Drawer, IDENTITY};
5use gl;
6use gl::types::*;
7use resources::Resource;
8use shader::*;
9use std;
10use std::ops::{Index, IndexMut};
11use texture::Texture;
12use vertex::*;
13
14/// Vertex Buffer structure
15#[derive(Debug, Clone, PartialEq)]
16/// A vertexbuffer is an buffer object in OpenGl.
17/// Here it's linked with VertexArray for data.
18/// The VertexBuffer is the 'low levelest' object that is drawable.
19/// You can create it from Vertice slice or VertexArray
20/// ```no_run
21/// use gust::window::Window;
22/// use gust::vertex::{VertexArray, Vertex};
23/// use gust::Drawable;
24///
25/// fn main() {
26///     let win = Window::default();
27///     let vertice = &[
28///     Vertex::new(Vector::new(0.0, 0.0), Vector::new(0.0, 0.0), Color::new(1.0, 0.0, 0.0)),
29///     Vertex::new(Vector::new(1.0, 0.0), Vector::new(0.0, 0.0), Color::new(1.0, 0.0, 0.0)),
30///     Vertex::new(Vector::new(0.0, 1.0), Vector::new(0.0, 0.0), Color::new(1.0, 0.0, 0.0)),
31///     ];
32///     let triangle = VertexBuffer::from(vertice);
33///     while window.is_open() {
34///         window.clear();
35///         window.draw(&triangle);
36///         window.display();
37///     }
38/// }
39/// ```
40pub struct VertexBuffer {
41    id: u32,
42    texture: Option<Resource<Texture>>,
43    array: VertexArray,
44    primitive: GLenum,
45    len: usize,
46}
47
48#[derive(Debug, Clone, PartialEq, Copy, Hash)]
49pub enum Primitive {
50    Triangles,
51    Quads,
52    TrianglesStrip,
53    TriangleFan,
54    Points,
55    Lines,
56}
57
58impl Primitive {
59    /// Get primitive type
60    pub fn get_gl_type(self) -> GLenum {
61        match self {
62            Primitive::Quads => gl::QUADS,
63            Primitive::Triangles => gl::TRIANGLES,
64            Primitive::Points => gl::POINTS,
65            Primitive::Lines => gl::LINES,
66            Primitive::TrianglesStrip => gl::TRIANGLE_STRIP,
67            Primitive::TriangleFan => gl::TRIANGLE_STRIP,
68        }
69    }
70
71    pub fn get_primitive(prim: GLenum) -> Primitive {
72        match prim {
73            gl::QUADS => Primitive::Quads,
74            gl::TRIANGLES => Primitive::Triangles,
75            gl::TRIANGLE_STRIP => Primitive::TrianglesStrip,
76            gl::LINES => Primitive::Lines,
77            gl::TRIANGLE_FAN => Primitive::TriangleFan,
78            _ => Primitive::Points,
79        }
80    }
81}
82
83impl Into<GLenum> for Primitive {
84    fn into(self) -> GLenum {
85        self.get_gl_type()
86    }
87}
88
89impl VertexBuffer {
90    fn clear_gl() {
91        unsafe {
92            gl::BindBuffer(gl::ARRAY_BUFFER, 0);
93            gl::BindVertexArray(0);
94        }
95    }
96
97    /// Clear all data from VertexArray
98    pub fn clear(&mut self) {
99        self.array.clear();
100    }
101
102    /// Create new Vertex Buffer from vertices
103    pub fn new(t: Primitive, vertice: VertexArray) -> VertexBuffer {
104        let mut buffer_id: u32 = 0;
105
106        unsafe {
107            gl::GenBuffers(1, &mut buffer_id);
108            // --------------------------------
109            // Buffers generations heere
110            // we create a vertexArray and a buffer.
111            // Then we Bind the VertexArray the buffer
112            // to the openGl state machine.
113            // After we put data inside the buffer.
114            // Then we cut the data inside the buffer in 3
115            // { 1.0, 1.0, 0.0, 1.0, 3.0, 3.0 }
116            // |   pos  | texCoord |  color  |
117            // |        |          |         |
118            // With the 3 VertexAttribPointer
119            // --------------------------------
120
121            vertice.bind();
122            gl::BindBuffer(gl::ARRAY_BUFFER, buffer_id);
123            // Put data inside
124            gl::BufferData(
125                gl::ARRAY_BUFFER,
126                (std::mem::size_of::<GLfloat>() * vertice.len() * 8) as GLsizeiptr,
127                vertice.get_ptr(),
128                gl::STATIC_DRAW,
129            );
130            vertice.active();
131        };
132
133        let vertex_buffer = VertexBuffer {
134            id: buffer_id,
135            texture: None,
136            primitive: Self::get_gl_type(t),
137            len: vertice.len(),
138            array: vertice,
139        };
140        Self::clear_gl();
141
142        vertex_buffer
143    }
144
145    /// Append data to the actual VertexArray while be updated internaly.
146    pub fn append(&mut self, vertices: &[Vertex]) {
147        self.array.array_mut().append(&mut Vec::from(vertices));
148    }
149
150    /// Get primitive type
151    fn get_gl_type(prim: Primitive) -> GLenum {
152        match prim {
153            Primitive::Quads => gl::QUADS,
154            Primitive::Triangles => gl::TRIANGLES,
155            Primitive::Points => gl::POINTS,
156            Primitive::Lines => gl::LINES,
157            Primitive::TrianglesStrip => gl::TRIANGLE_STRIP,
158            Primitive::TriangleFan => gl::TRIANGLE_FAN,
159        }
160    }
161
162    fn set_texture(&mut self, texture: &Resource<Texture>) {
163        self.texture = Some(Resource::clone(texture));
164    }
165
166    pub fn get_primitive(&self) -> Primitive {
167        match self.primitive {
168            gl::QUADS => Primitive::Quads,
169            gl::TRIANGLES => Primitive::Triangles,
170            gl::TRIANGLE_STRIP => Primitive::TrianglesStrip,
171            gl::LINES => Primitive::Lines,
172            gl::TRIANGLE_FAN => Primitive::TriangleFan,
173            _ => Primitive::Points,
174        }
175    }
176
177    pub fn set_geometry(&mut self, vertice: &[Vertex]) {
178        self.array = VertexArray::from(vertice);
179    }
180
181    #[inline]
182    pub fn bind(&self) {
183        unsafe {
184            gl::BindBuffer(gl::ARRAY_BUFFER, self.id);
185        }
186    }
187
188    #[inline]
189    pub fn unbind(&self) {
190        unsafe {
191            gl::BindBuffer(gl::ARRAY_BUFFER, 0);
192        }
193    }
194}
195
196impl DrawableMut for VertexBuffer {
197    fn draw_mut<T: Drawer>(&mut self, target: &mut T) {
198        self.update();
199        self.draw(target);
200    }
201
202    fn draw_with_context_mut(&mut self, context: &mut Context) {
203        self.update();
204        self.draw_with_context(context);
205    }
206}
207
208impl Drawable for VertexBuffer {
209    fn draw<T: Drawer>(&self, target: &mut T) {
210        let texture = if let Some(ref rc_texture) = self.texture {
211            Some(rc_texture.as_ref())
212        } else {
213            None
214        };
215
216        let mut context = Context::new(
217            texture,
218            if texture.is_none() {
219                &*NO_TEXTURE_SHADER
220            } else {
221                &*DEFAULT_SHADER
222            },
223            vec![
224                ("transform".to_string(), &*IDENTITY),
225                ("projection".to_string(), target.projection()),
226            ],
227            BlendMode::Alpha,
228        );
229
230        unsafe {
231            self.setup_draw(&mut context);
232            self.array.bind();
233            self.bind();
234            gl::DrawArrays(self.primitive, 0, self.array.len() as i32);
235            self.unbind();
236        }
237    }
238
239    fn draw_with_context(&self, context: &mut Context) {
240        unsafe {
241            self.setup_draw(context);
242            self.array.bind();
243            self.bind();
244            gl::DrawArrays(self.primitive, 0, self.array.len() as i32);
245            self.unbind();
246        }
247    }
248
249    fn update(&mut self) {
250        unsafe {
251            self.array.bind();
252            self.bind();
253
254            if self.len != self.array.len() {
255                gl::BufferData(
256                    gl::ARRAY_BUFFER,
257                    (std::mem::size_of::<GLfloat>() * self.array.len() * 8) as GLsizeiptr,
258                    self.array.get_ptr(),
259                    gl::STATIC_DRAW,
260                );
261                self.len = self.array.len();
262            }
263            gl::BufferSubData(
264                gl::ARRAY_BUFFER,
265                0,
266                (std::mem::size_of::<GLfloat>() * self.array.len() * 8) as GLsizeiptr,
267                self.array.get_ptr(),
268            );
269            self.array.active();
270            self.unbind();
271            self.array.unbind();
272        }
273    }
274}
275
276impl Index<usize> for VertexBuffer {
277    type Output = Vertex;
278
279    fn index(&self, vertex_index: usize) -> &Vertex {
280        &self.array[vertex_index]
281    }
282}
283
284impl IndexMut<usize> for VertexBuffer {
285    fn index_mut(&mut self, index: usize) -> &mut Vertex {
286        &mut self.array[index]
287    }
288}
289
290impl Default for VertexBuffer {
291    fn default() -> Self {
292        VertexBuffer::new(Primitive::Triangles, VertexArray::new())
293    }
294}
295
296impl Drop for VertexBuffer {
297    fn drop(&mut self) {
298        unsafe {
299            gl::DeleteBuffers(1, &[self.id] as *const _);
300        }
301        println!("Buffer {} deleted.", self.id);
302    }
303}