use super::{
buffer::{Buffer, BufferType, MappedBuffer, Usage},
vertex::{Vertex, VertexFormat},
Context,
};
fn to_bytes<'a, V>(data: &'a [V]) -> &'a [u8]
where
V: Sized,
{
unsafe {
std::slice::from_raw_parts::<'a, u8>(
data.as_ptr() as *const _,
data.len() * std::mem::size_of::<V>(),
)
}
}
fn from_bytes<'a, V>(data: &'a [u8]) -> &'a [V]
where
V: Sized,
{
unsafe {
std::slice::from_raw_parts::<'a, V>(
data.as_ptr() as *const _,
data.len() / std::mem::size_of::<V>(),
)
}
}
fn set_buffer<T>(buffer: &mut MappedBuffer, data: &[T], offset: usize)
where
T: Sized,
{
buffer.write(to_bytes(data), offset * std::mem::size_of::<T>());
}
fn get_buffer<T>(buffer: &MappedBuffer) -> &[T]
where
T: Sized,
{
from_bytes(buffer.memory_map())
}
pub type BindingInfo<'a> = (&'a VertexFormat, usize, u32, super::BufferKey, BufferType);
#[derive(Debug)]
pub struct VertexMesh<V> {
vbo: Buffer,
draw_range: Option<std::ops::Range<usize>>,
draw_mode: super::DrawMode,
type_marker: std::marker::PhantomData<V>,
}
impl<V> VertexMesh<V>
where
V: Vertex,
{
pub fn new(ctx: &mut Context, size: usize) -> Result<Self, super::GraphicsError> {
let vbo = Buffer::new(
ctx,
size * std::mem::size_of::<V>(),
BufferType::Vertex,
Usage::Dynamic,
)?;
Ok(Self::with_buffer(vbo))
}
pub fn with_data(ctx: &mut Context, vertices: &[V]) -> Result<Self, super::GraphicsError> {
let vbo = Buffer::with_data(ctx, to_bytes(vertices), BufferType::Vertex, Usage::Dynamic)?;
Ok(Self::with_buffer(vbo))
}
pub fn with_buffer(buffer: Buffer) -> Self {
Self {
vbo: buffer,
draw_range: None,
draw_mode: super::DrawMode::Triangles,
type_marker: std::marker::PhantomData,
}
}
pub fn set_vertices(&self, ctx: &mut super::Context, vertices: &[V], offset: usize) {
ctx.bind_buffer(self.vbo.handle(), self.vbo.buffer_type());
ctx.buffer_static_draw(
&self.vbo,
to_bytes(vertices),
offset * std::mem::size_of::<V>(),
)
}
pub fn set_draw_range(&mut self, draw_range: Option<std::ops::Range<usize>>) {
self.draw_range = draw_range;
}
pub fn set_draw_mode(&mut self, draw_mode: super::DrawMode) {
self.draw_mode = draw_mode;
}
pub fn draw_range(&self) -> std::ops::Range<usize> {
self.draw_range.clone().unwrap_or(0..(self.len()))
}
pub fn draw_mode(&self) -> super::DrawMode {
self.draw_mode
}
pub fn len(&self) -> usize {
self.vbo.size() / std::mem::size_of::<V>()
}
}
pub struct MappedVertexMesh<V> {
inner: VertexMesh<V>,
memory_map: MappedBuffer,
}
impl<V> MappedVertexMesh<V>
where
V: Vertex,
{
pub fn new(ctx: &mut super::Context, size: usize) -> Result<Self, super::GraphicsError> {
let inner = VertexMesh::new(ctx, size)?;
let memory_map =
MappedBuffer::with_shape(inner.vbo.clone(), [size * std::mem::size_of::<V>()]);
Ok(Self { inner, memory_map })
}
pub fn set_vertices(&mut self, vertices: &[V], offset: usize) {
set_buffer(&mut self.memory_map, vertices, offset)
}
pub fn get_vertices(&self) -> &[V] {
get_buffer(&self.memory_map)
}
pub fn unmap(&mut self, ctx: &mut super::Context) -> &VertexMesh<V> {
self.memory_map.unmap(ctx);
&self.inner
}
}
#[derive(Debug)]
pub struct IndexedMesh<V, I> {
mesh: VertexMesh<V>,
ibo: Buffer,
type_marker: std::marker::PhantomData<I>,
}
impl<V, I> IndexedMesh<V, I>
where
V: Vertex,
I: Index,
{
pub fn new(
ctx: &mut Context,
vertex_count: usize,
index_count: usize,
) -> Result<Self, super::GraphicsError> {
let ibo = Buffer::new(
ctx,
index_count * std::mem::size_of::<I>(),
BufferType::Index,
Usage::Dynamic,
)?;
let mesh = VertexMesh::new(ctx, vertex_count)?;
Ok(Self {
mesh,
ibo,
type_marker: std::marker::PhantomData,
})
}
pub fn with_data(
ctx: &mut Context,
vertices: &[V],
indices: &[I],
) -> Result<Self, super::GraphicsError> {
let ibo = Buffer::with_data(ctx, to_bytes(indices), BufferType::Index, Usage::Dynamic)?;
let mesh = VertexMesh::with_data(ctx, vertices)?;
Ok(Self {
mesh,
ibo,
type_marker: std::marker::PhantomData,
})
}
pub fn with_mesh(
ctx: &mut Context,
mesh: VertexMesh<V>,
index_count: usize,
) -> Result<Self, super::GraphicsError> {
let ibo = Buffer::new(
ctx,
index_count * std::mem::size_of::<I>(),
BufferType::Index,
mesh.vbo.usage(),
)?;
Ok(Self {
mesh,
ibo,
type_marker: std::marker::PhantomData,
})
}
pub fn set_vertices(&self, ctx: &mut Context, vertices: &[V], offset: usize) {
self.mesh.set_vertices(ctx, vertices, offset)
}
pub fn set_indices(&self, ctx: &mut Context, indices: &[I], offset: usize) {
ctx.bind_buffer(self.ibo.handle(), self.ibo.buffer_type());
ctx.buffer_static_draw(
&self.ibo,
to_bytes(indices),
offset * std::mem::size_of::<I>(),
)
}
pub fn set_draw_range(&mut self, draw_range: Option<std::ops::Range<usize>>) {
self.mesh.set_draw_range(draw_range)
}
pub fn draw_range(&self) -> std::ops::Range<usize> {
self.mesh
.draw_range
.clone()
.unwrap_or(0..(self.ibo.size() / std::mem::size_of::<I>()))
}
pub fn set_draw_mode(&mut self, draw_mode: super::DrawMode) {
self.mesh.set_draw_mode(draw_mode)
}
}
#[derive(Debug)]
pub struct MappedIndexedMesh<V, I> {
inner: IndexedMesh<V, I>,
vbo: MappedBuffer,
ibo: MappedBuffer,
}
impl<V, I> MappedIndexedMesh<V, I>
where
V: Vertex,
I: Index,
{
pub fn new(
gl: &mut Context,
vertex_count: usize,
index_count: usize,
) -> Result<Self, super::GraphicsError> {
let inner = IndexedMesh::new(gl, vertex_count, index_count)?;
let vbo = MappedBuffer::with_shape(inner.mesh.vbo.clone(), inner.mesh.vbo.size());
let ibo = MappedBuffer::with_shape(inner.ibo.clone(), inner.ibo.size());
Ok(Self { inner, vbo, ibo })
}
pub fn with_data(
ctx: &mut Context,
vertices: Vec<V>,
indices: Vec<I>,
) -> Result<Self, super::GraphicsError> {
let inner = IndexedMesh::with_data(ctx, &vertices, &indices)?;
let vbo = MappedBuffer::from_vec(inner.mesh.vbo.clone(), unsafe {
let mut vertices = std::mem::ManuallyDrop::new(vertices);
Vec::from_raw_parts(
vertices.as_mut_ptr() as *mut _,
vertices.len() * std::mem::size_of::<V>(),
vertices.capacity() * std::mem::size_of::<V>(),
)
});
let ibo = MappedBuffer::from_vec(inner.ibo.clone(), unsafe {
let mut indices = std::mem::ManuallyDrop::new(indices);
Vec::from_raw_parts(
indices.as_mut_ptr() as *mut _,
indices.len() * std::mem::size_of::<I>(),
indices.capacity() * std::mem::size_of::<I>(),
)
});
Ok(Self { inner, vbo, ibo })
}
pub fn vertex_capacity(&self) -> usize {
self.vbo.memory_map.len() / std::mem::size_of::<V>()
}
pub fn index_capacity(&self) -> usize {
self.ibo.memory_map.len() / std::mem::size_of::<I>()
}
pub fn set_draw_range(&mut self, draw_range: Option<std::ops::Range<usize>>) {
self.inner.set_draw_range(draw_range)
}
pub fn draw_range(&self) -> std::ops::Range<usize> {
self.inner.draw_range()
}
pub fn set_vertices(&mut self, vertices: &[V], offset: usize) {
set_buffer(&mut self.vbo, vertices, offset)
}
pub fn get_vertices(&self) -> &[V] {
get_buffer(&self.vbo)
}
pub fn set_indices(&mut self, indices: &[I], offset: usize) {
set_buffer(&mut self.ibo, indices, offset)
}
pub fn get_indices(&self) -> &[I] {
get_buffer(&self.ibo)
}
pub fn unmap(&mut self, ctx: &mut Context) -> &IndexedMesh<V, I> {
self.vbo.unmap(ctx);
self.ibo.unmap(ctx);
&self.inner
}
}
#[derive(Clone, Debug)]
pub struct AttachedAttributes<'a> {
pub buffer: &'a Buffer,
pub formats: &'a [VertexFormat],
pub step: u32,
pub stride: usize,
}
pub trait Mesh {
fn attachments(&self) -> Vec<AttachedAttributes>;
fn draw(
&self,
ctx: &mut super::Context,
draw_range: std::ops::Range<usize>,
draw_mode: super::DrawMode,
instance_count: usize,
);
}
impl<V: Vertex> Mesh for VertexMesh<V> {
fn attachments(&self) -> Vec<AttachedAttributes> {
vec![AttachedAttributes {
buffer: &self.vbo,
formats: V::build_bindings(),
step: 0,
stride: std::mem::size_of::<V>(),
}]
}
fn draw(
&self,
ctx: &mut super::Context,
draw_range: std::ops::Range<usize>,
draw_mode: super::DrawMode,
instance_count: usize,
) {
if draw_range.start >= draw_range.end {
return;
}
let (count, offset) = (
(draw_range.end - draw_range.start) as i32,
draw_range.start as i32,
);
if instance_count > 1 {
ctx.draw_arrays_instanced(draw_mode, offset, count, instance_count as i32);
} else {
ctx.draw_arrays(draw_mode, offset, count);
}
}
}
impl<V: Vertex> Mesh for &VertexMesh<V> {
fn attachments(&self) -> Vec<AttachedAttributes> {
VertexMesh::attachments(self)
}
fn draw(
&self,
ctx: &mut super::Context,
draw_range: std::ops::Range<usize>,
draw_mode: super::DrawMode,
instance_count: usize,
) {
VertexMesh::draw(self, ctx, draw_range, draw_mode, instance_count)
}
}
impl<V: Vertex, I: Index> Mesh for IndexedMesh<V, I> {
fn attachments(&self) -> Vec<AttachedAttributes> {
self.mesh.attachments()
}
fn draw(
&self,
ctx: &mut super::Context,
draw_range: std::ops::Range<usize>,
draw_mode: super::DrawMode,
instance_count: usize,
) {
if draw_range.start >= draw_range.end {
return;
}
let (count, offset) = (
(draw_range.end - draw_range.start) as i32,
draw_range.start as i32,
);
let ibo = &self.ibo;
ctx.bind_buffer(ibo.handle(), ibo.buffer_type());
if instance_count > 1 {
ctx.draw_elements_instanced(
draw_mode,
count,
I::GL_TYPE,
offset,
instance_count as i32,
);
} else {
ctx.draw_elements(draw_mode, count, I::GL_TYPE, offset);
}
}
}
impl<V: Vertex, I: Index> Mesh for &IndexedMesh<V, I> {
fn attachments(&self) -> Vec<AttachedAttributes> {
IndexedMesh::attachments(self)
}
fn draw(
&self,
ctx: &mut super::Context,
draw_range: std::ops::Range<usize>,
draw_mode: super::DrawMode,
instance_count: usize,
) {
IndexedMesh::draw(self, ctx, draw_range, draw_mode, instance_count)
}
}
pub struct MultiMesh<'a, T> {
base: T,
attachments: Vec<AttachedAttributes<'a>>,
}
impl<'a, T> MultiMesh<'a, T> {
pub fn new(base: T, attachments: Vec<AttachedAttributes<'a>>) -> Self {
Self { base, attachments }
}
}
impl<'a, T> Mesh for MultiMesh<'a, T>
where
T: Mesh,
{
fn attachments(&self) -> Vec<AttachedAttributes> {
self.attachments.clone()
}
fn draw(
&self,
ctx: &mut Context,
draw_range: std::ops::Range<usize>,
draw_mode: super::DrawMode,
instance_count: usize,
) {
self.base.draw(ctx, draw_range, draw_mode, instance_count)
}
}
pub trait MeshAttacher: Mesh {
fn attach<'a, T: Mesh>(&'a self, other: &'a T) -> MultiMesh<&'a Self> {
Self::attach_with_step(self, other, 0)
}
fn attach_with_step<'a, T: Mesh>(&'a self, other: &'a T, step: u32) -> MultiMesh<&'a Self> {
let mut attachments = self.attachments();
attachments.extend(other.attachments().into_iter().map(|mut a| {
a.step = step;
a
}));
MultiMesh {
base: self,
attachments,
}
}
}
impl<V: Vertex> MeshAttacher for VertexMesh<V> {}
impl<V: Vertex, I: Index> MeshAttacher for IndexedMesh<V, I> {}
pub trait Index {
const GL_TYPE: u32;
}
impl Index for u32 {
const GL_TYPE: u32 = glow::UNSIGNED_INT;
}
impl Index for u16 {
const GL_TYPE: u32 = glow::UNSIGNED_SHORT;
}