#[cfg(feature = "std")]
use std::cell::RefCell;
#[cfg(feature = "std")]
use std::cmp::Ordering;
#[cfg(feature = "std")]
use std::fmt;
#[cfg(feature = "std")]
use std::marker::PhantomData;
#[cfg(feature = "std")]
use std::mem;
#[cfg(feature = "std")]
use std::ops::{Deref, DerefMut};
#[cfg(feature = "std")]
use std::os::raw::c_void;
#[cfg(feature = "std")]
use std::ptr;
#[cfg(feature = "std")]
use std::rc::Rc;
#[cfg(feature = "std")]
use std::slice;
#[cfg(not(feature = "std"))]
use alloc::rc::Rc;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
#[cfg(not(feature = "std"))]
use core::cell::RefCell;
#[cfg(not(feature = "std"))]
use core::cmp::Ordering;
#[cfg(not(feature = "std"))]
use core::fmt;
#[cfg(not(feature = "std"))]
use core::marker::PhantomData;
#[cfg(not(feature = "std"))]
use core::mem;
#[cfg(not(feature = "std"))]
use core::ops::{Deref, DerefMut};
#[cfg(not(feature = "std"))]
use core::ptr;
#[cfg(not(feature = "std"))]
use core::slice;
use crate::context::GraphicsContext;
use crate::linear::{M22, M33, M44};
use crate::metagl::*;
use crate::state::GraphicsState;
#[derive(Debug, Eq, PartialEq)]
pub enum BufferError {
Overflow(usize, usize),
TooFewValues(usize, usize),
TooManyValues(usize, usize),
MapFailed,
}
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 unsafe 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;
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,
len,
state: ctx.state().clone(),
},
_t: PhantomData,
}
}
pub fn from_slice<C, S>(
ctx: &mut C,
slice: S
) -> Buffer<T>
where C: GraphicsContext,
S: AsRef<[T]> {
let mut buffer: GLuint = 0;
let slice = slice.as_ref();
let len = slice.len();
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,
slice.as_ptr() as *const c_void,
gl::STREAM_DRAW,
);
}
Buffer {
raw: RawBuffer {
handle: buffer,
bytes,
len,
state: ctx.state().clone(),
},
_t: PhantomData,
}
}
pub fn repeat<C>(ctx: &mut C, len: usize, value: T) -> Self where C: GraphicsContext, T: Copy {
let mut buf = unsafe { Self::new(ctx, len) };
buf.clear(value).unwrap();
buf
}
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(&mut 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(&mut self, x: T) -> Result<(), BufferError> where T: Copy {
self.write_whole(&vec![x; self.len])
}
pub fn fill<V>(&mut self, values: V) -> Result<(), BufferError> where V: AsRef<[T]> {
self.write_whole(values.as_ref())
}
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(&mut 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(crate) fn as_slice<T>(&mut 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(crate) 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 })
}
}
#[inline(always)]
pub(crate) fn handle(&self) -> GLuint {
self.handle
}
#[inline(always)]
pub fn len(&self) -> usize {
self.len
}
}
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 IntoIter = slice::Iter<'b, T>;
type Item = &'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 IntoIter = slice::Iter<'b, T>;
type Item = &'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 IntoIter = slice::IterMut<'b, T>;
type Item = &'b mut 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);