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) -> 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 (), gl::STATIC_DRAW ); } 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); 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]) } 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; } } pub struct IndexBuffer { id: u32, // Not bytes. Number of indexes. len: usize, max: u32, } impl IndexBuffer { pub fn from_slice (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 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; } }