use std::cell::{Ref, RefCell}; use std::mem::size_of; use std::ops::{Deref, DerefMut}; use std::ptr::null; use std::rc::Rc; use std::slice::from_raw_parts_mut; use crate::{ error::Error, misc::{AsEnum, Bindable}, }; /* Buffer */ pub struct Buffer { id: gl::GLuint, size: usize, } impl Buffer { pub fn new() -> Result { let mut id = 0; Error::checked(|| gl::create_buffers(1, &mut id))?; Ok(Self { id, size: 0 }) } pub fn id(&self) -> gl::GLuint { self.id } pub fn size(&self) -> usize { self.size } pub fn buffer_data(&mut self, usage: Usage, data: &[T]) -> Result<(), Error> { let size = data.len() * size_of::(); Error::checked(|| { gl::named_buffer_data( self.id, size as gl::GLsizeiptr, data.as_ptr() as *const _, usage.as_enum(), ) })?; self.size = size; Ok(()) } pub fn buffer_size(&mut self, usage: Usage, size: usize) -> Result<(), Error> { Error::checked(|| { gl::named_buffer_data(self.id, size as gl::GLsizeiptr, null(), usage.as_enum()) })?; self.size = size; Ok(()) } pub fn map(&self) -> Result, Error> { Ok(Map { data: self.inner_map(gl::READ_ONLY)?, buf: self, }) } pub fn map_mut(&mut self, write_only: bool) -> Result, Error> { Ok(MapMut { data: self.inner_map(if write_only { gl::WRITE_ONLY } else { gl::READ_WRITE })?, buf: self, }) } pub fn map_range( &self, byte_offset: usize, value_count: Option, ) -> Result, Error> { Ok(Map { data: self.inner_map_range(gl::READ_ONLY, byte_offset, value_count)?, buf: self, }) } pub fn map_range_mut( &mut self, write_only: bool, byte_offset: usize, value_count: Option, ) -> Result, Error> { let access = if write_only { gl::WRITE_ONLY } else { gl::READ_WRITE }; Ok(MapMut { data: self.inner_map_range(access, byte_offset, value_count)?, buf: self, }) } pub fn bind_buffer_base(&self, target: Target, index: gl::GLuint) { gl::bind_buffer_base(target.as_enum(), index, self.id); } pub fn bind_buffer_range( &self, target: Target, index: gl::GLuint, offset: gl::GLintptr, size: gl::GLsizeiptr, ) { gl::bind_buffer_range(target.as_enum(), index, self.id, offset, size); } fn inner_map(&self, access: gl::GLenum) -> Result<&mut [T], Error> { let ptr = Error::err_if(&null(), gl::map_named_buffer(self.id, access))?; let count = self.size / size_of::(); Ok(unsafe { from_raw_parts_mut(ptr as *mut T, count) }) } pub fn inner_map_range( &self, access: gl::GLenum, byte_offset: usize, value_count: Option, ) -> Result<&mut [T], Error> { let count = value_count.unwrap_or_else(|| { if self.size > byte_offset { (self.size - byte_offset) / size_of::() } else { 0 } }); if byte_offset + count * size_of::() > self.size { return Err(Error::InvalidParameter); } let size = count * size_of::(); let ptr = Error::err_if( &null(), gl::map_named_buffer_range(self.id, byte_offset as isize, size as isize, access), )?; Ok(unsafe { from_raw_parts_mut(ptr as *mut T, count) }) } } impl Drop for Buffer { fn drop(&mut self) { gl::delete_buffers(1, &self.id); } } impl Bindable for (Target, T) where T: Deref, { fn bind(&self) { gl::bind_buffer(self.0.as_enum(), self.1.id); } fn unbind(&self) { gl::bind_buffer(self.0.as_enum(), 0); } } /* Map */ pub struct Map<'a, T> { buf: &'a Buffer, data: &'a [T], } impl Drop for Map<'_, T> { fn drop(&mut self) { gl::unmap_named_buffer(self.buf.id); } } impl Deref for Map<'_, T> { type Target = [T]; fn deref(&self) -> &Self::Target { self.data } } /* MapMut */ pub struct MapMut<'a, T> { buf: &'a Buffer, data: &'a mut [T], } impl Drop for MapMut<'_, T> { fn drop(&mut self) { gl::unmap_named_buffer(self.buf.id); } } impl Deref for MapMut<'_, T> { type Target = [T]; fn deref(&self) -> &Self::Target { self.data } } impl DerefMut for MapMut<'_, T> { fn deref_mut(&mut self) -> &mut Self::Target { self.data } } /* BufferRef */ pub trait BufferRef { type Output: Deref; fn as_ref(self) -> Self::Output; } impl<'a> BufferRef for &'a Buffer { type Output = &'a Buffer; fn as_ref(self) -> Self::Output { self } } impl<'a> BufferRef for &'a RefCell { type Output = Ref<'a, Buffer>; fn as_ref(self) -> Self::Output { self.borrow() } } impl<'a> BufferRef for &'a Rc> { type Output = Ref<'a, Buffer>; fn as_ref(self) -> Self::Output { self.borrow() } } /* Target */ #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum Target { ArrayBuffer, AtomicCounterBuffer, CopyReadBuffer, CopyWriteBuffer, DispatchIndirectBuffer, DrawIndirectBuffer, ElementArrayBuffer, PixelPackBuffer, PixelUnpackBuffer, QueryBuffer, ShaderStorageBuffer, TextureBuffer, TransformFeedbackBuffer, UniformBuffer, } impl AsEnum for Target { fn as_enum(&self) -> gl::GLenum { match self { Self::ArrayBuffer => gl::ARRAY_BUFFER, Self::AtomicCounterBuffer => gl::ATOMIC_COUNTER_BUFFER, Self::CopyReadBuffer => gl::COPY_READ_BUFFER, Self::CopyWriteBuffer => gl::COPY_WRITE_BUFFER, Self::DispatchIndirectBuffer => gl::DISPATCH_INDIRECT_BUFFER, Self::DrawIndirectBuffer => gl::DRAW_INDIRECT_BUFFER, Self::ElementArrayBuffer => gl::ELEMENT_ARRAY_BUFFER, Self::PixelPackBuffer => gl::PIXEL_PACK_BUFFER, Self::PixelUnpackBuffer => gl::PIXEL_UNPACK_BUFFER, Self::QueryBuffer => gl::QUERY_BUFFER, Self::ShaderStorageBuffer => gl::SHADER_STORAGE_BUFFER, Self::TextureBuffer => gl::TEXTURE_BUFFER, Self::TransformFeedbackBuffer => gl::TRANSFORM_FEEDBACK_BUFFER, Self::UniformBuffer => gl::UNIFORM_BUFFER, } } } /* Usage */ pub enum Usage { StreamDraw, StreamRead, StreamCopy, StaticDraw, StaticRead, StatidCopy, DynamicDraw, DynamicRead, DynamicCopy, } impl AsEnum for Usage { fn as_enum(&self) -> gl::GLenum { match self { Self::StreamDraw => gl::STREAM_DRAW, Self::StreamRead => gl::STREAM_READ, Self::StreamCopy => gl::STREAM_COPY, Self::StaticDraw => gl::STATIC_DRAW, Self::StaticRead => gl::STATIC_READ, Self::StatidCopy => gl::STATIC_COPY, Self::DynamicDraw => gl::DYNAMIC_DRAW, Self::DynamicRead => gl::DYNAMIC_READ, Self::DynamicCopy => gl::DYNAMIC_COPY, } } }