|
- 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<Self, Error> {
- 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<T>(&mut self, usage: Usage, data: &[T]) -> Result<(), Error> {
- let size = data.len() * size_of::<T>();
-
- 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<T>(&self) -> Result<Map<'_, T>, Error> {
- Ok(Map {
- data: self.inner_map(gl::READ_ONLY)?,
- buf: self,
- })
- }
-
- pub fn map_mut<T>(&mut self, write_only: bool) -> Result<MapMut<'_, T>, Error> {
- Ok(MapMut {
- data: self.inner_map(if write_only {
- gl::WRITE_ONLY
- } else {
- gl::READ_WRITE
- })?,
- buf: self,
- })
- }
-
- pub fn map_range<T>(
- &self,
- byte_offset: usize,
- value_count: Option<usize>,
- ) -> Result<Map<'_, T>, Error> {
- Ok(Map {
- data: self.inner_map_range(gl::READ_ONLY, byte_offset, value_count)?,
- buf: self,
- })
- }
-
- pub fn map_range_mut<T>(
- &mut self,
- write_only: bool,
- byte_offset: usize,
- value_count: Option<usize>,
- ) -> Result<MapMut<'_, T>, 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<T>(&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::<T>();
-
- Ok(unsafe { from_raw_parts_mut(ptr as *mut T, count) })
- }
-
- pub fn inner_map_range<T>(
- &self,
- access: gl::GLenum,
- byte_offset: usize,
- value_count: Option<usize>,
- ) -> Result<&mut [T], Error> {
- let count = value_count.unwrap_or_else(|| {
- if self.size > byte_offset {
- (self.size - byte_offset) / size_of::<T>()
- } else {
- 0
- }
- });
-
- if byte_offset + count * size_of::<T>() > self.size {
- return Err(Error::InvalidParameter);
- }
-
- let size = count * size_of::<T>();
- 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<T> Bindable for (Target, T)
- where
- T: Deref<Target = Buffer>,
- {
- 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<T> Drop for Map<'_, T> {
- fn drop(&mut self) {
- gl::unmap_named_buffer(self.buf.id);
- }
- }
-
- impl<T> 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<T> Drop for MapMut<'_, T> {
- fn drop(&mut self) {
- gl::unmap_named_buffer(self.buf.id);
- }
- }
-
- impl<T> Deref for MapMut<'_, T> {
- type Target = [T];
-
- fn deref(&self) -> &Self::Target {
- self.data
- }
- }
-
- impl<T> DerefMut for MapMut<'_, T> {
- fn deref_mut(&mut self) -> &mut Self::Target {
- self.data
- }
- }
-
- /* BufferRef */
-
- pub trait BufferRef {
- type Output: Deref<Target = Buffer>;
-
- 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<Buffer> {
- type Output = Ref<'a, Buffer>;
-
- fn as_ref(self) -> Self::Output {
- self.borrow()
- }
- }
-
- impl<'a> BufferRef for &'a Rc<RefCell<Buffer>> {
- 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,
- }
- }
- }
|