189 lines
3.4 KiB
Rust
189 lines
3.4 KiB
Rust
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,
|
|
}
|
|
|
|
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,
|
|
}
|
|
}
|
|
|
|
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,
|
|
}
|
|
}
|
|
|
|
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 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::<LittleEndian> ().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,
|
|
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,
|
|
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;
|
|
}
|
|
}
|