use byteorder::{LittleEndian, ReadBytesExt}; use std::cmp; use std::convert::TryInto; use std::ffi::c_void; use std::io::Cursor; // Only contains f32 floats pub struct VertexBuffer { id: u32, // Not bytes. len: usize, } const FLOAT_SIZE: usize = 4; impl VertexBuffer { // len is the number of floats fn allocate_buffer (len: usize, usage: u32) -> u32 { let mut id = 0; unsafe { gl::GenBuffers (1, &mut id); gl::BindBuffer (gl::ARRAY_BUFFER, id); // Khronos docs say that null is not derefed here gl::BufferData ( gl::ARRAY_BUFFER, (len * FLOAT_SIZE).try_into ().unwrap (), std::ptr::null (), usage ); } assert! (id != 0); id } pub fn from_slices (slices: &[&[f32]]) -> Self { let len = slices.iter () .map (|slice| slice.len ()) .sum (); let id = Self::allocate_buffer (len, gl::STATIC_DRAW); let mut offset = 0; for slice in slices.iter () { unsafe { gl::BufferSubData ( gl::ARRAY_BUFFER, (offset * FLOAT_SIZE).try_into ().unwrap (), (len * FLOAT_SIZE).try_into ().unwrap (), &slice [0] as *const f32 as *const c_void ); } offset += slice.len (); } Self { id, len, } } pub fn from_slice (slice: &[f32]) -> Self { Self::from_slices (&[slice]) } // len is the number of floats pub fn streaming (len: usize) -> Self { let id = Self::allocate_buffer (len, gl::STREAM_DRAW); Self { id, len, } } pub fn bind (&self) { unsafe { gl::BindBuffer (gl::ARRAY_BUFFER, self.id); } } } impl Drop for VertexBuffer { fn drop (&mut self) { if self.id == 0 { return; } unsafe { gl::DeleteBuffers (1, &self.id); } self.id = 0; } } /// A buffer of triangle indices in OpenGL server memory pub struct IndexBuffer { /// The OpenGL ID of the buffer id: u32, /// The count of 32-bit indices the buffer can store len: usize, /// The largest index stored in the buffer when it was created max: u32, } impl IndexBuffer { /// Interprets a u8 slice as a u32 slice pub fn from_slice_u8 (slice: &[u8]) -> Self { let mut rdr = Cursor::new (slice); let mut max = None; const IDX_SIZE: usize = 4; assert_eq! (slice.len () % IDX_SIZE, 0); for _ in 0..slice.len () / IDX_SIZE { let idx = rdr.read_u32:: ().unwrap (); max = match max { None => Some (idx), Some (max) => Some (cmp::max (max, idx)), }; } let id = { let mut id = 0; unsafe { gl::GenBuffers (1, &mut id); gl::BindBuffer (gl::ELEMENT_ARRAY_BUFFER, id); gl::BufferData (gl::ELEMENT_ARRAY_BUFFER, slice.len ().try_into ().unwrap (), &slice [0] as *const u8 as *const c_void, gl::STATIC_DRAW); } assert! (id != 0); id }; Self { id, len: slice.len () / IDX_SIZE, max: max.unwrap (), } } pub fn from_slice_u32 (slice: &[u32]) -> Self { let max = slice.iter ().max (); let id = { let mut id = 0; unsafe { gl::GenBuffers (1, &mut id); gl::BindBuffer (gl::ELEMENT_ARRAY_BUFFER, id); gl::BufferData (gl::ELEMENT_ARRAY_BUFFER, (slice.len () * 4).try_into ().unwrap (), &slice [0] as *const u32 as *const c_void, gl::STATIC_DRAW); } assert! (id != 0); id }; Self { id, len: slice.len (), max: *max.unwrap (), } } pub fn bind (&self) { unsafe { gl::BindBuffer (gl::ELEMENT_ARRAY_BUFFER, self.id); } } pub fn max (&self) -> u32 { self.max } } impl Drop for IndexBuffer { fn drop (&mut self) { if self.id == 0 { return; } unsafe { gl::DeleteBuffers (1, &self.id); } self.id = 0; } }