use gl;
use gl::types::*;
use std::cell::RefCell;
use std::cmp::Ordering;
use std::error::Error;
use std::fmt;
use std::marker::PhantomData;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::os::raw::c_void;
use std::ptr;
use std::rc::Rc;
use std::slice;
use std::vec::Vec;
use context::GraphicsContext;
use linear::{M22, M33, M44};
use state::GraphicsState;
#[derive(Debug, Eq, PartialEq)]
pub enum BufferError {
Overflow(usize, usize),
TooFewValues(usize, usize),
TooManyValues(usize, usize),
MapFailed
}
impl Error for BufferError {}
impl fmt::Display for BufferError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
BufferError::Overflow(i, size) => {
write!(f, "buffer overflow (index = {}, size = {})", i, size)
}
BufferError::TooFewValues(nb, size) => {
write!(f, "too few values passed to the buffer (nb = {}, size = {})", nb, size)
}
BufferError::TooManyValues(nb, size) => {
write!(f, "too many values passed to the buffer (nb = {}, size = {})", nb, size)
}
BufferError::MapFailed => {
write!(f, "buffer mapping failed")
}
}
}
}
pub struct Buffer<T> {
raw: RawBuffer,
_t: PhantomData<T>
}
impl<T> Buffer<T> {
pub fn new<C>(ctx: &mut C, len: usize) -> Buffer<T> where C: GraphicsContext {
let mut buffer: GLuint = 0;
let bytes = mem::size_of::<T>() * len;
unsafe {
gl::GenBuffers(1, &mut buffer);
ctx.state().borrow_mut().bind_array_buffer(buffer);
gl::BufferData(gl::ARRAY_BUFFER, bytes as isize, ptr::null(), gl::STREAM_DRAW);
}
Buffer {
raw: RawBuffer {
handle: buffer,
bytes: bytes,
len: len,
state: ctx.state().clone(),
},
_t: PhantomData
}
}
#[inline(always)]
pub fn len(&self) -> usize {
self.len
}
pub fn at(&self, i: usize) -> Option<T> where T: Copy {
if i >= self.len {
return None;
}
unsafe {
self.raw.state.borrow_mut().bind_array_buffer(self.handle);
let ptr = gl::MapBuffer(gl::ARRAY_BUFFER, gl::READ_ONLY) as *const T;
let x = *ptr.offset(i as isize);
let _ = gl::UnmapBuffer(gl::ARRAY_BUFFER);
Some(x)
}
}
pub fn whole(&self) -> Vec<T> where T: Copy {
unsafe {
self.raw.state.borrow_mut().bind_array_buffer(self.handle);
let ptr = gl::MapBuffer(gl::ARRAY_BUFFER, gl::READ_ONLY) as *mut T;
let values = Vec::from_raw_parts(ptr, self.len, self.len);
let _ = gl::UnmapBuffer(gl::ARRAY_BUFFER);
values
}
}
pub fn set(&mut self, i: usize, x: T) -> Result<(), BufferError> where T: Copy {
if i >= self.len {
return Err(BufferError::Overflow(i, self.len));
}
unsafe {
self.raw.state.borrow_mut().bind_array_buffer(self.handle);
let ptr = gl::MapBuffer(gl::ARRAY_BUFFER, gl::WRITE_ONLY) as *mut T;
*ptr.offset(i as isize) = x;
let _ = gl::UnmapBuffer(gl::ARRAY_BUFFER);
}
Ok(())
}
pub fn write_whole(&self, values: &[T]) -> Result<(), BufferError> {
let len = values.len();
let in_bytes = len * mem::size_of::<T>();
let real_bytes = match in_bytes.cmp(&self.bytes) {
Ordering::Less => return Err(BufferError::TooFewValues(len, self.len)),
Ordering::Greater => return Err(BufferError::TooManyValues(len, self.len)),
_ => in_bytes
};
unsafe {
self.raw.state.borrow_mut().bind_array_buffer(self.handle);
let ptr = gl::MapBuffer(gl::ARRAY_BUFFER, gl::WRITE_ONLY);
ptr::copy_nonoverlapping(values.as_ptr() as *const c_void, ptr, real_bytes);
let _ = gl::UnmapBuffer(gl::ARRAY_BUFFER);
}
Ok(())
}
pub fn clear(&self, x: T) -> Result<(), BufferError> where T: Copy {
self.write_whole(&vec![x; self.len])
}
pub fn fill(&self, values: &[T]) -> Result<(), BufferError> {
self.write_whole(values)
}
pub fn to_raw(self) -> RawBuffer {
let raw = RawBuffer {
handle: self.raw.handle,
bytes: self.raw.bytes,
len: self.raw.len,
state: self.raw.state.clone()
};
mem::forget(self);
raw
}
pub fn as_slice(&self) -> Result<BufferSlice<T>, BufferError> {
self.raw.as_slice()
}
pub fn as_slice_mut(&mut self) -> Result<BufferSliceMut<T>, BufferError> {
self.raw.as_slice_mut()
}
}
impl<T> Deref for Buffer<T> {
type Target = RawBuffer;
fn deref(&self) -> &Self::Target {
&self.raw
}
}
impl<T> DerefMut for Buffer<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.raw
}
}
pub struct RawBuffer {
handle: GLuint,
bytes: usize,
len: usize,
state: Rc<RefCell<GraphicsState>>
}
impl RawBuffer {
pub fn as_slice<T>(&self) -> Result<BufferSlice<T>, BufferError> {
unsafe {
self.state.borrow_mut().bind_array_buffer(self.handle);
let ptr = gl::MapBuffer(gl::ARRAY_BUFFER, gl::READ_ONLY) as *const T;
if ptr.is_null() {
return Err(BufferError::MapFailed);
}
Ok(BufferSlice {
raw: self,
ptr
})
}
}
pub fn as_slice_mut<T>(&mut self) -> Result<BufferSliceMut<T>, BufferError> {
unsafe {
self.state.borrow_mut().bind_array_buffer(self.handle);
let ptr = gl::MapBuffer(gl::ARRAY_BUFFER, gl::READ_WRITE) as *mut T;
if ptr.is_null() {
return Err(BufferError::MapFailed);
}
Ok(BufferSliceMut {
raw: self,
ptr
})
}
}
pub(crate) fn handle(&self) -> GLuint {
self.handle
}
}
impl Drop for RawBuffer {
fn drop(&mut self) {
unsafe { gl::DeleteBuffers(1, &self.handle) }
}
}
impl<T> From<Buffer<T>> for RawBuffer {
fn from(buffer: Buffer<T>) -> Self {
buffer.to_raw()
}
}
pub struct BufferSlice<'a, T> where T: 'a {
raw: &'a RawBuffer,
ptr: *const T
}
impl<'a, T> Drop for BufferSlice<'a, T> where T: 'a {
fn drop(&mut self) {
unsafe {
self.raw.state.borrow_mut().bind_array_buffer(self.raw.handle);
gl::UnmapBuffer(gl::ARRAY_BUFFER);
}
}
}
impl<'a, T> Deref for BufferSlice<'a, T> where T: 'a {
type Target = [T];
fn deref(&self) -> &Self::Target {
unsafe { slice::from_raw_parts(self.ptr, self.raw.len) }
}
}
impl<'a, 'b, T> IntoIterator for &'b BufferSlice<'a, T> where T: 'a {
type Item = &'b T;
type IntoIter = slice::Iter<'b, T>;
fn into_iter(self) -> Self::IntoIter {
self.deref().into_iter()
}
}
pub struct BufferSliceMut<'a, T> where T: 'a {
raw: &'a RawBuffer,
ptr: *mut T
}
impl<'a, T> Drop for BufferSliceMut<'a, T> where T: 'a {
fn drop(&mut self) {
unsafe {
self.raw.state.borrow_mut().bind_array_buffer(self.raw.handle);
gl::UnmapBuffer(gl::ARRAY_BUFFER);
}
}
}
impl<'a, 'b, T> IntoIterator for &'b BufferSliceMut<'a, T> where T: 'a {
type Item = &'b T;
type IntoIter = slice::Iter<'b, T>;
fn into_iter(self) -> Self::IntoIter {
self.deref().into_iter()
}
}
impl<'a, 'b, T> IntoIterator for &'b mut BufferSliceMut<'a, T> where T: 'a {
type Item = &'b mut T;
type IntoIter = slice::IterMut<'b, T>;
fn into_iter(self) -> Self::IntoIter {
self.deref_mut().into_iter()
}
}
impl<'a, T> Deref for BufferSliceMut<'a, T> where T: 'a {
type Target = [T];
fn deref(&self) -> &Self::Target {
unsafe { slice::from_raw_parts(self.ptr, self.raw.len) }
}
}
impl<'a, T> DerefMut for BufferSliceMut<'a, T> where T: 'a {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { slice::from_raw_parts_mut(self.ptr, self.raw.len) }
}
}
pub unsafe trait UniformBlock {}
unsafe impl UniformBlock for u8 {}
unsafe impl UniformBlock for u16 {}
unsafe impl UniformBlock for u32 {}
unsafe impl UniformBlock for i8 {}
unsafe impl UniformBlock for i16 {}
unsafe impl UniformBlock for i32 {}
unsafe impl UniformBlock for f32 {}
unsafe impl UniformBlock for f64 {}
unsafe impl UniformBlock for bool {}
unsafe impl UniformBlock for M22 {}
unsafe impl UniformBlock for M33 {}
unsafe impl UniformBlock for M44 {}
unsafe impl UniformBlock for [u8; 2] {}
unsafe impl UniformBlock for [u16; 2] {}
unsafe impl UniformBlock for [u32; 2] {}
unsafe impl UniformBlock for [i8; 2] {}
unsafe impl UniformBlock for [i16; 2] {}
unsafe impl UniformBlock for [i32; 2] {}
unsafe impl UniformBlock for [f32; 2] {}
unsafe impl UniformBlock for [f64; 2] {}
unsafe impl UniformBlock for [bool; 2] {}
unsafe impl UniformBlock for [u8; 3] {}
unsafe impl UniformBlock for [u16; 3] {}
unsafe impl UniformBlock for [u32; 3] {}
unsafe impl UniformBlock for [i8; 3] {}
unsafe impl UniformBlock for [i16; 3] {}
unsafe impl UniformBlock for [i32; 3] {}
unsafe impl UniformBlock for [f32; 3] {}
unsafe impl UniformBlock for [f64; 3] {}
unsafe impl UniformBlock for [bool; 3] {}
unsafe impl UniformBlock for [u8; 4] {}
unsafe impl UniformBlock for [u16; 4] {}
unsafe impl UniformBlock for [u32; 4] {}
unsafe impl UniformBlock for [i8; 4] {}
unsafe impl UniformBlock for [i16; 4] {}
unsafe impl UniformBlock for [i32; 4] {}
unsafe impl UniformBlock for [f32; 4] {}
unsafe impl UniformBlock for [f64; 4] {}
unsafe impl UniformBlock for [bool; 4] {}
unsafe impl<T> UniformBlock for [T] where T: UniformBlock {}
macro_rules! impl_uniform_block_tuple {
($( $t:ident ),*) => {
unsafe impl<$($t),*> UniformBlock for ($($t),*) where $($t: UniformBlock),* {}
}
}
impl_uniform_block_tuple!(A, B);
impl_uniform_block_tuple!(A, B, C);
impl_uniform_block_tuple!(A, B, C, D);
impl_uniform_block_tuple!(A, B, C, D, E);
impl_uniform_block_tuple!(A, B, C, D, E, F);
impl_uniform_block_tuple!(A, B, C, D, E, F, G);
impl_uniform_block_tuple!(A, B, C, D, E, F, G, H);
impl_uniform_block_tuple!(A, B, C, D, E, F, G, H, I);
impl_uniform_block_tuple!(A, B, C, D, E, F, G, H, I, J);