use core::mem;
use core::ops::Drop;
use gl;
use gl::types::*;
use super::{BufferTarget, Usage};
#[derive(Debug, Clone, Hash)]
pub struct GLBuffer {
id: GLuint,
stride: usize,
kind: BufferTarget,
usage: Usage,
size: usize,
kind_size: usize,
length: usize,
}
impl GLBuffer {
#[inline]
pub fn new<T>(kind: BufferTarget, stride: usize, usage: Usage, data: &[T]) -> Self {
let mut id = 0;
let length = data.len();
let kind_size = mem::size_of::<T>();
let size = kind_size * length;
let gl_kind = kind.to_gl();
let gl_usage = usage.to_gl();
unsafe {
gl::GenBuffers(1, &mut id);
gl::BindBuffer(gl_kind, id);
gl::BufferData(gl_kind, size as GLsizeiptr, data.as_ptr() as *const GLvoid, gl_usage);
};
GLBuffer {
id: id,
stride: stride * kind_size,
kind: kind,
usage: usage,
size: size,
kind_size: kind_size,
length: length,
}
}
#[inline(always)]
pub fn id(&self) -> GLuint { self.id }
#[inline(always)]
pub fn stride(&self) -> usize { self.stride }
#[inline(always)]
pub fn kind(&self) -> &BufferTarget { &self.kind }
#[inline(always)]
pub fn usage(&self) -> &Usage { &self.usage }
#[inline(always)]
pub fn size(&self) -> usize { self.size }
#[inline(always)]
pub fn kind_size(&self) -> usize { self.kind_size }
#[inline(always)]
pub fn length(&self) -> usize { self.length }
#[inline]
pub fn bind(&self) -> &Self {
unsafe { gl::BindBuffer(self.kind.to_gl(), self.id); }
self
}
#[inline]
pub fn unbind(&self) -> &Self {
unsafe { gl::BindBuffer(self.kind.to_gl(), 0); }
self
}
#[inline]
pub fn update<T>(&mut self, data: &[T]) -> &mut Self {
let length = data.len();
let kind_size = mem::size_of::<T>();
let size = kind_size * length;
let gl_kind = self.kind.to_gl();
let gl_usage = self.usage.to_gl();
unsafe {
gl::BindBuffer(gl_kind, self.id);
gl::BufferData(gl_kind, size as GLsizeiptr, data.as_ptr() as *const GLvoid, gl_usage);
};
self.size = size;
self.kind_size = kind_size;
self.length = length;
self
}
}
impl Drop for GLBuffer {
#[inline]
fn drop(&mut self) {
if self.id != 0 {
unsafe { gl::DeleteBuffers(1, &self.id); }
}
}
}