use super::BufferKey;
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum BufferType {
Vertex,
Index,
}
impl From<BufferType> for u32 {
fn from(ty: BufferType) -> Self {
match ty {
BufferType::Vertex => glow::ARRAY_BUFFER,
BufferType::Index => glow::ELEMENT_ARRAY_BUFFER,
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Usage {
Stream,
Static,
Dynamic,
}
impl Usage {
pub fn to_gl(self) -> u32 {
match self {
Usage::Stream => glow::STREAM_DRAW,
Usage::Static => glow::STATIC_DRAW,
Usage::Dynamic => glow::DYNAMIC_DRAW,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Buffer {
size: usize,
handle: BufferKey,
buffer_type: BufferType,
usage: Usage,
}
impl Buffer {
pub fn new(
ctx: &mut super::Context,
size: usize,
buffer_type: BufferType,
usage: Usage,
) -> Result<Self, super::GraphicsError> {
let handle = ctx.new_buffer(size, buffer_type, usage, None)?;
Ok(Self {
size,
handle,
buffer_type,
usage,
})
}
pub fn with_data(
ctx: &mut super::Context,
data: &[u8],
buffer_type: BufferType,
usage: Usage,
) -> Result<Self, super::GraphicsError> {
let size = data.len();
let handle = ctx.new_buffer(size, buffer_type, usage, Some(data))?;
Ok(Self {
size,
handle,
buffer_type,
usage,
})
}
pub fn handle(&self) -> BufferKey {
self.handle
}
pub fn size(&self) -> usize {
self.size
}
pub fn buffer_type(&self) -> BufferType {
self.buffer_type
}
pub fn usage(&self) -> Usage {
self.usage
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct ModifiedRange<D> {
pub offset: D,
pub size: D,
}
#[derive(Debug, PartialEq)]
pub struct Mapped<T, D: ndarray::Dimension> {
pub(crate) inner: T,
pub(crate) memory_map: ndarray::Array<u8, D>,
pub(crate) modified_range: Option<ModifiedRange<D>>,
}
impl<T, D> Mapped<T, D>
where
D: ndarray::Dimension,
{
pub fn with_shape<S>(inner: T, shape: S) -> Self
where
S: ndarray::ShapeBuilder<Dim = D>,
{
Self {
inner,
memory_map: ndarray::Array::default(shape),
modified_range: None,
}
}
pub fn inner(&self) -> &T {
&self.inner
}
pub fn memory_map(&self) -> &[u8] {
self.memory_map.as_slice_memory_order().unwrap()
}
}
impl<T> Mapped<T, ndarray::Ix1> {
pub fn from_vec(inner: T, vec: Vec<u8>) -> Self {
Self {
inner,
memory_map: vec.into(),
modified_range: None,
}
}
pub fn write(&mut self, data: &[u8], offset: usize) {
self.memory_map.as_slice_memory_order_mut().unwrap()[offset..(offset + data.len())]
.copy_from_slice(data);
self.set_modified_range(offset, data.len());
}
pub fn modified_range(&self) -> Option<ModifiedRange<usize>> {
self.modified_range.map(|range| ModifiedRange {
offset: range.offset[0],
size: range.size[0],
})
}
fn set_modified_range(&mut self, offset: usize, modified_size: usize) {
let range = self.modified_range.get_or_insert(ModifiedRange {
offset: ndarray::Ix1(0),
size: ndarray::Ix1(0),
});
let old_range_end = range.offset + range.size;
range.offset = ndarray::Ix1(std::cmp::min(range.offset[0], offset));
let new_range_end = std::cmp::max(offset + modified_size, old_range_end[0]);
range.size = ndarray::Ix1(new_range_end - range.offset[0]);
}
}
pub type MappedBuffer = Mapped<Buffer, ndarray::Ix1>;
impl MappedBuffer {
pub fn with_buffer(
ctx: &mut super::Context,
size: usize,
buffer_type: BufferType,
usage: Usage,
) -> Result<Self, super::GraphicsError> {
let inner = Buffer::new(ctx, size, buffer_type, usage)?;
let memory_map = ndarray::Array1::from(vec![0u8; inner.size()]);
Ok(Self {
inner,
memory_map,
modified_range: None,
})
}
pub fn unmap(&mut self, ctx: &mut super::Context) {
ctx.unmap_buffer(self);
self.modified_range = None;
}
}