2021-32-bit-holiday-jam/src/gpu_buffers.rs

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;
}
}