gtether 0.2.3

Highly concurrent multiplayer focused game engine, with an emphasis on realtime streamable asset management.
Documentation
use std::sync::Arc;
use vulkano::buffer::{AllocateBufferError, Buffer, BufferContents, BufferCreateInfo, BufferUsage, IndexBuffer, Subbuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer};
use vulkano::memory::allocator::{AllocationCreateInfo, MemoryTypeFilter};
use vulkano::pipeline::graphics::vertex_input::Vertex;
use vulkano::{Validated, ValidationError};

use crate::render::EngineDevice;

pub mod obj;

#[derive(BufferContents, Vertex, Debug, Clone)]
#[repr(C)]
pub struct ModelVertex {
    #[format(R32G32B32_SFLOAT)]
    position: glm::TVec3<f32>,
}

#[derive(BufferContents, Vertex, Debug, Clone)]
#[repr(C)]
pub struct ModelVertexNormal {
    #[format(R32G32B32_SFLOAT)]
    position: glm::TVec3<f32>,
    #[format(R32G32B32_SFLOAT)]
    normal: glm::TVec3<f32>,
}

#[derive(BufferContents, Vertex, Debug, Clone)]
#[repr(C)]
pub struct ModelVertexNormalColor {
    #[format(R32G32B32_SFLOAT)]
    position: glm::TVec3<f32>,
    #[format(R32G32B32_SFLOAT)]
    normal: glm::TVec3<f32>,
    #[format(R32G32B32_SFLOAT)]
    color: glm::TVec3<f32>,
}

#[derive(BufferContents, Vertex, Debug, Clone)]
#[repr(C)]
pub struct ModelVertexNormalTex {
    #[format(R32G32B32_SFLOAT)]
    position: glm::TVec3<f32>,
    #[format(R32G32B32_SFLOAT)]
    normal: glm::TVec3<f32>,
    #[format(R32G32_SFLOAT)]
    tex_coord: glm::TVec2<f32>,
}

pub trait Index: BufferContents {
    #[inline]
    fn create_subbuffer<I>(
        device: &Arc<EngineDevice>,
        iter: I,
    ) -> Result<Subbuffer<[Self]>, Validated<AllocateBufferError>>
    where
        Self: Sized,
        I: IntoIterator<Item=Self>,
        I::IntoIter: ExactSizeIterator,
    {
        Buffer::from_iter(
            device.memory_allocator().clone(),
            BufferCreateInfo {
                usage: BufferUsage::INDEX_BUFFER,
                ..Default::default()
            },
            AllocationCreateInfo {
                memory_type_filter: MemoryTypeFilter::PREFER_DEVICE | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
                ..Default::default()
            },
            iter,
        )
    }

    fn create_index_buffer<I>(
        device: &Arc<EngineDevice>,
        iter: I,
    ) -> Result<IndexBuffer, Validated<AllocateBufferError>>
    where
        I: IntoIterator<Item=Self>,
        I::IntoIter: ExactSizeIterator;
}

impl Index for u8 {
    #[inline]
    fn create_index_buffer<I>(
        device: &Arc<EngineDevice>,
        iter: I,
    ) -> Result<IndexBuffer, Validated<AllocateBufferError>>
    where
        I: IntoIterator<Item=Self>,
        I::IntoIter: ExactSizeIterator,
    {
        Self::create_subbuffer(device, iter).map(Into::into)
    }
}

impl Index for u16 {
    #[inline]
    fn create_index_buffer<I>(
        device: &Arc<EngineDevice>,
        iter: I,
    ) -> Result<IndexBuffer, Validated<AllocateBufferError>>
    where
        I: IntoIterator<Item=Self>,
        I::IntoIter: ExactSizeIterator,
    {
        Self::create_subbuffer(device, iter).map(Into::into)
    }
}

impl Index for u32 {
    #[inline]
    fn create_index_buffer<I>(
        device: &Arc<EngineDevice>,
        iter: I,
    ) -> Result<IndexBuffer, Validated<AllocateBufferError>>
    where
        I: IntoIterator<Item=Self>,
        I::IntoIter: ExactSizeIterator,
    {
        Self::create_subbuffer(device, iter).map(Into::into)
    }
}

#[derive(Debug)]
pub struct Model<V: Vertex> {
    vertex_buffer: Subbuffer<[V]>,
    index_buffer: Option<IndexBuffer>,
}

impl<V: Vertex> Model<V> {
    #[inline]
    pub fn from_buffers(
        vertex_buffer: Subbuffer<[V]>,
        index_buffer: Option<impl Into<IndexBuffer>>,
    ) -> Self {
        Self {
            vertex_buffer,
            index_buffer: index_buffer.map(Into::into),
        }
    }

    pub fn from_raw<I, IV, II>(
        device: &Arc<EngineDevice>,
        vertices: IV,
        indices: Option<II>,
    ) -> Result<Self, Validated<AllocateBufferError>>
    where
        I: Index,
        IV: IntoIterator<Item=V>,
        IV::IntoIter: ExactSizeIterator,
        II: IntoIterator<Item=I>,
        II::IntoIter: ExactSizeIterator,
    {
        let vertex_buffer = Buffer::from_iter(
            device.memory_allocator().clone(),
            BufferCreateInfo {
                usage: BufferUsage::VERTEX_BUFFER,
                ..Default::default()
            },
            AllocationCreateInfo {
                memory_type_filter: MemoryTypeFilter::PREFER_DEVICE | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
                ..Default::default()
            },
            vertices,
        )?;
        let index_buffer = indices
            .map(|indices| I::create_index_buffer(device, indices))
            .transpose()?;

        Ok(Self::from_buffers(
            vertex_buffer,
            index_buffer,
        ))
    }

    #[inline]
    pub fn vertex_buffer(&self) -> &Subbuffer<[V]> {
        &self.vertex_buffer
    }

    #[inline]
    pub fn index_buffer(&self) -> Option<&IndexBuffer> {
        self.index_buffer.as_ref()
    }

    pub fn draw(
        &self,
        builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
    ) -> Result<(), Box<ValidationError>> {
        builder.bind_vertex_buffers(0, self.vertex_buffer.clone())?;
        if let Some(index_buffer) = &self.index_buffer {
            builder
                .bind_index_buffer(index_buffer.clone())?
                .draw_indexed(index_buffer.len() as u32, 1, 0, 0, 0)?;
        } else {
            builder.draw(self.vertex_buffer.len() as u32, 1, 0, 0)?;
        }
        Ok(())
    }

    pub fn draw_instanced<I: Vertex>(
        &self,
        builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
        instance_buffer: Subbuffer<[I]>,
    ) -> Result<(), Box<ValidationError>> {
        let instance_buffer_len = instance_buffer.len() as u32;
        builder.bind_vertex_buffers(0, (
            self.vertex_buffer.clone(),
            instance_buffer,
        ))?;
        if let Some(index_buffer) = &self.index_buffer {
            builder
                .bind_index_buffer(index_buffer.clone())?
                .draw_indexed(index_buffer.len() as u32, instance_buffer_len, 0, 0, 0)?;
        } else {
            builder.draw(self.vertex_buffer.len() as u32, instance_buffer_len, 0, 0)?;
        }
        Ok(())
    }
}