dunge 0.3.0-alpha

Simple and portable 3d render library
Documentation
use {
    crate::{
        context::Context,
        state::State,
        types::{self, MatrixType, MemberType, ScalarType, VectorType},
    },
    std::marker::PhantomData,
    wgpu::Buffer,
};

pub struct Uniform<V> {
    buf: Buffer,
    vert: PhantomData<V>,
}

impl<V> Uniform<V> {
    pub(crate) fn new(state: &State, contents: &[u8]) -> Self {
        use wgpu::{
            util::{BufferInitDescriptor, DeviceExt},
            BufferUsages,
        };

        let buf = {
            let desc = BufferInitDescriptor {
                label: None,
                contents,
                usage: BufferUsages::UNIFORM | BufferUsages::COPY_DST,
            };

            state.device().create_buffer_init(&desc)
        };

        Self {
            buf,
            vert: PhantomData,
        }
    }

    pub fn update(&self, cx: &Context, val: V)
    where
        V: Value,
    {
        let queue = cx.state().queue();
        let data = val.value();
        queue.write_buffer(&self.buf, 0, data.as_ref());
    }

    pub(crate) fn buffer(&self) -> &Buffer {
        &self.buf
    }
}

pub trait Value: private::Sealed {
    const TYPE: MemberType;
    type Type;
    type Data: AsRef<[u8]>;
    fn value(self) -> Self::Data;
}

impl private::Sealed for f32 {}

impl Value for f32 {
    const TYPE: MemberType = MemberType::Scalar(ScalarType::Float);
    type Type = Self;
    type Data = Data;

    fn value(self) -> Self::Data {
        Data([self, 0., 0., 0.])
    }
}

impl private::Sealed for [f32; 2] {}

impl Value for [f32; 2] {
    const TYPE: MemberType = MemberType::Vector(VectorType::Vec2f);
    type Type = types::Vec2<f32>;
    type Data = Data;

    fn value(self) -> Self::Data {
        let [x, y] = self;
        Data([x, y, 0., 0.])
    }
}

impl private::Sealed for [f32; 3] {}

impl Value for [f32; 3] {
    const TYPE: MemberType = MemberType::Vector(VectorType::Vec3f);
    type Type = types::Vec3<f32>;
    type Data = Data;

    fn value(self) -> Self::Data {
        let [x, y, z] = self;
        Data([x, y, z, 0.])
    }
}

impl private::Sealed for [f32; 4] {}

impl Value for [f32; 4] {
    const TYPE: MemberType = MemberType::Vector(VectorType::Vec4f);
    type Type = types::Vec4<f32>;
    type Data = Data;

    fn value(self) -> Self::Data {
        Data(self)
    }
}

impl private::Sealed for glam::Vec2 {}

impl Value for glam::Vec2 {
    const TYPE: MemberType = MemberType::Vector(VectorType::Vec2f);
    type Type = types::Vec2<f32>;
    type Data = Data;

    fn value(self) -> Self::Data {
        self.to_array().value()
    }
}

impl private::Sealed for glam::Vec3 {}

impl Value for glam::Vec3 {
    const TYPE: MemberType = MemberType::Vector(VectorType::Vec3f);
    type Type = types::Vec3<f32>;
    type Data = Data;

    fn value(self) -> Self::Data {
        self.to_array().value()
    }
}

impl private::Sealed for glam::Vec4 {}

impl Value for glam::Vec4 {
    const TYPE: MemberType = MemberType::Vector(VectorType::Vec4f);
    type Type = types::Vec4<f32>;
    type Data = Data;

    fn value(self) -> Self::Data {
        self.to_array().value()
    }
}

impl private::Sealed for glam::Mat2 {}

impl Value for glam::Mat2 {
    const TYPE: MemberType = MemberType::Matrix(MatrixType::Mat2);
    type Type = types::Mat2;
    type Data = Data;

    fn value(self) -> Self::Data {
        self.to_cols_array().value()
    }
}

impl private::Sealed for glam::Mat3 {}

impl Value for glam::Mat3 {
    const TYPE: MemberType = MemberType::Matrix(MatrixType::Mat3);
    type Type = types::Mat3;
    type Data = Data<9>;

    fn value(self) -> Self::Data {
        Data(self.to_cols_array())
    }
}

impl private::Sealed for glam::Mat4 {}

impl Value for glam::Mat4 {
    const TYPE: MemberType = MemberType::Matrix(MatrixType::Mat4);
    type Type = types::Mat4;
    type Data = Data<16>;

    fn value(self) -> Self::Data {
        Data(self.to_cols_array())
    }
}

pub struct Data<const N: usize = 4>([f32; N]);

impl<const N: usize> AsRef<[u8]> for Data<N> {
    fn as_ref(&self) -> &[u8] {
        bytemuck::cast_slice(&self.0)
    }
}

mod private {
    pub trait Sealed {}
}