srs2dge-core 0.2.0

Simple Rust 2D Game Engine
Documentation
use crate::{label, target::Target, Frame};
use bytemuck::Pod;
use std::{marker::PhantomData, mem, num::NonZeroU64, ops::RangeBounds};
use wgpu::{
    util::{BufferInitDescriptor, DeviceExt},
    BufferAddress, BufferDescriptor, BufferUsages,
};

//

pub use index::*;
pub use indirect::*;
pub use uniform::*;
pub use vertex::*;

//

pub mod index;
pub mod indirect;
pub mod prelude;
pub mod uniform;
pub mod vertex;

//

#[derive(Debug)]
pub struct Buffer<T, const USAGE: u32> {
    buffer: wgpu::Buffer,
    elements: usize,
    _p: PhantomData<T>,
}

#[derive(Debug, Clone, Copy)]
pub struct BufferSlice<'b, T, const USAGE: u32> {
    slice: wgpu::BufferSlice<'b>,
    _p: PhantomData<T>,
}

//

impl<T, const USAGE: u32> Buffer<T, USAGE>
where
    T: Pod,
{
    pub fn new_with(target: &Target, data: &[T]) -> Self {
        let buffer = target.device.create_buffer_init(&BufferInitDescriptor {
            label: label!(),
            usage: BufferUsages::from_bits_truncate(USAGE),
            contents: bytemuck::cast_slice(data),
        });

        Self::with_buffer(buffer, data.len())
    }

    pub fn new_single(target: &Target, data: T) -> Self {
        let buffer = target.device.create_buffer_init(&BufferInitDescriptor {
            label: label!(),
            usage: BufferUsages::from_bits_truncate(USAGE),
            contents: bytemuck::cast_slice(&[data]),
        });

        Self::with_buffer(buffer, 1)
    }

    pub fn upload(&self, target: &mut Target, frame: &mut Frame, new_data: &[T]) {
        let mut mapping = frame.write_buffer(
            &self.buffer,
            0,
            NonZeroU64::new(Self::size_of(self.elements) as _).unwrap(),
            &target.device,
        );

        let new_data = bytemuck::cast_slice(new_data);
        mapping[..new_data.len()].copy_from_slice(new_data);
    }
}

impl<T, const USAGE: u32> Buffer<T, USAGE>
where
    T: Pod,
{
    pub fn new(target: &Target, elements: usize) -> Self {
        let buffer = target.device.create_buffer(&BufferDescriptor {
            label: label!(),
            size: Self::size_of(elements) as _,
            usage: BufferUsages::from_bits_truncate(USAGE),
            mapped_at_creation: false,
        });

        Self::with_buffer(buffer, elements)
    }

    pub fn inner(&self) -> &wgpu::Buffer {
        &self.buffer
    }

    pub fn capacity(&self) -> usize {
        self.elements
    }

    pub fn slice<S>(&self, range: S) -> BufferSlice<T, USAGE>
    where
        S: RangeBounds<BufferAddress>,
    {
        BufferSlice {
            slice: self.buffer.slice(range),
            _p: PhantomData::default(),
        }
    }

    fn with_buffer(buffer: wgpu::Buffer, elements: usize) -> Self {
        Self {
            buffer,
            elements,
            _p: Default::default(),
        }
    }

    fn size_of(elements: usize) -> usize {
        mem::size_of::<T>() * elements
    }
}

impl<'b, T, const USAGE: u32> BufferSlice<'b, T, USAGE> {
    pub fn inner(&self) -> wgpu::BufferSlice {
        self.slice
    }
}

//

pub trait AsBufferSlice<T, const USAGE: u32> {
    fn as_slice(&self) -> BufferSlice<T, USAGE>;
}

//

impl<T, const USAGE: u32> AsBufferSlice<T, USAGE> for Buffer<T, USAGE>
where
    T: Pod,
{
    fn as_slice(&self) -> BufferSlice<T, USAGE> {
        self.slice(..)
    }
}

impl<'b, T, const USAGE: u32> AsBufferSlice<T, USAGE> for BufferSlice<'b, T, USAGE>
where
    T: Pod,
{
    fn as_slice(&self) -> Self {
        *self
    }
}