1use 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#[derive(Debug, Clone, PartialEq)]
16pub 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 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 pub fn clear(&mut self) {
99 self.array.clear();
100 }
101
102 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 vertice.bind();
122 gl::BindBuffer(gl::ARRAY_BUFFER, buffer_id);
123 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 pub fn append(&mut self, vertices: &[Vertex]) {
147 self.array.array_mut().append(&mut Vec::from(vertices));
148 }
149
150 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}