ferrum-wgpu 0.1.1

3D rendering engine library
Documentation
use cgmath::{Matrix3, Matrix4, One, Quaternion, Vector3, Zero};

use crate::renderer;

pub trait Vertex {
    fn desc() -> wgpu::VertexBufferLayout<'static>;
}

#[repr(C)]
#[derive(Debug, Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)]
pub struct ModelVertex {
    pub position: [f32; 3],
    pub text_cords: [f32; 2],
    pub normal: [f32; 3],
    pub color: [f32; 3],
    pub tangent: [f32; 3],
    pub bitangent: [f32; 3],
}

impl Vertex for ModelVertex {
    fn desc() -> wgpu::VertexBufferLayout<'static> {
        use std::mem;
        wgpu::VertexBufferLayout {
            array_stride: mem::size_of::<ModelVertex>() as wgpu::BufferAddress,
            step_mode: wgpu::VertexStepMode::Vertex,
            attributes: &[
                wgpu::VertexAttribute {
                    offset: 0,
                    shader_location: 0,
                    format: wgpu::VertexFormat::Float32x3,
                },
                wgpu::VertexAttribute {
                    offset: mem::size_of::<[f32; 3]>() as wgpu::BufferAddress,
                    shader_location: 1,
                    format: wgpu::VertexFormat::Float32x2,
                },
                wgpu::VertexAttribute {
                    offset: mem::size_of::<[f32; 5]>() as wgpu::BufferAddress,
                    shader_location: 2,
                    format: wgpu::VertexFormat::Float32x3,
                },
                wgpu::VertexAttribute {
                    offset: mem::size_of::<[f32; 8]>() as wgpu::BufferAddress,
                    shader_location: 3,
                    format: wgpu::VertexFormat::Float32x3,
                },
                wgpu::VertexAttribute {
                    offset: mem::size_of::<[f32; 8]>() as wgpu::BufferAddress,
                    shader_location: 4,
                    format: wgpu::VertexFormat::Float32x3,
                },
                wgpu::VertexAttribute {
                    offset: mem::size_of::<[f32; 11]>() as wgpu::BufferAddress,
                    shader_location: 5,
                    format: wgpu::VertexFormat::Float32x3,
                },
            ],
        }
    }
}

pub trait DrawModel<'a> {
    fn draw_mesh(
        &mut self,
        mesh: &'a renderer::Mesh,
        material: &'a renderer::Material,
        instances: std::ops::Range<u32>,
        instance_buffer: &'a wgpu::Buffer,
        camera_bind_group: &'a wgpu::BindGroup,
        light_bind_group: &'a wgpu::BindGroup,
        shadow_bind_group: &'a wgpu::BindGroup,
        wind_bind_group: &'a wgpu::BindGroup,
    );

    fn draw_model(
        &mut self,
        model: &'a Model,
        camera_bind_group: &'a wgpu::BindGroup,
        light_bind_group: &'a wgpu::BindGroup,
        shadow_bind_group: &'a wgpu::BindGroup,
        wind_bind_group: &'a wgpu::BindGroup,
    );
}

impl<'a, 'b> DrawModel<'b> for wgpu::RenderPass<'a>
where
    'b: 'a,
{
    fn draw_mesh(
        &mut self,
        mesh: &'b renderer::Mesh,
        material: &'b renderer::Material,
        instances: std::ops::Range<u32>,
        instance_buffer: &'a wgpu::Buffer,
        camera_bind_group: &'b wgpu::BindGroup,
        light_bind_group: &'a wgpu::BindGroup,
        shadow_bind_group: &'a wgpu::BindGroup,
        wind_bind_group: &'a wgpu::BindGroup,
    ) {
        self.set_vertex_buffer(0, mesh.vertex_buffer.slice(..));
        self.set_vertex_buffer(1, instance_buffer.slice(..));
        self.set_index_buffer(mesh.index_buffer.slice(..), wgpu::IndexFormat::Uint32);
        self.set_bind_group(0, &material.bind_group, &[]);
        self.set_bind_group(1, camera_bind_group, &[]);
        self.set_bind_group(2, light_bind_group, &[]);
        self.set_bind_group(3, shadow_bind_group, &[]);
        self.set_bind_group(4, wind_bind_group, &[]);
        self.draw_indexed(0..mesh.indices, 0, instances);
    }

    fn draw_model(
        &mut self,
        model: &'b Model,
        camera_bind_group: &'b wgpu::BindGroup,
        light_bind_group: &'a wgpu::BindGroup,
        shadow_bind_group: &'a wgpu::BindGroup,
        wind_bind_group: &'a wgpu::BindGroup,
    ) {
        for mesh in &model.meshes {
            let material: &renderer::Material = &model.materials[mesh.material];
            self.draw_mesh(
                mesh,
                material,
                0..model.instances.len() as u32,
                &model.instance_buffer,
                camera_bind_group,
                light_bind_group,
                shadow_bind_group,
                wind_bind_group,
            );
        }
    }
}

#[repr(C)]
#[derive(Clone, Copy, Debug, bytemuck::Pod, bytemuck::Zeroable)]
#[allow(dead_code)]
pub struct InstanceRaw {
    pub model: [[f32; 4]; 4],
    pub normals: [[f32; 3]; 3],
    pub wind_weight: f32,
}

impl InstanceRaw {
    pub fn desc() -> wgpu::VertexBufferLayout<'static> {
        use std::mem;

        wgpu::VertexBufferLayout {
            array_stride: mem::size_of::<InstanceRaw>() as wgpu::BufferAddress,
            step_mode: wgpu::VertexStepMode::Instance,
            attributes: &[
                wgpu::VertexAttribute {
                    format: wgpu::VertexFormat::Float32x4,
                    offset: 0,
                    shader_location: 6,
                },
                wgpu::VertexAttribute {
                    format: wgpu::VertexFormat::Float32x4,
                    offset: mem::size_of::<[f32; 4]>() as wgpu::BufferAddress,
                    shader_location: 7,
                },
                wgpu::VertexAttribute {
                    format: wgpu::VertexFormat::Float32x4,
                    offset: mem::size_of::<[f32; 8]>() as wgpu::BufferAddress,
                    shader_location: 8,
                },
                wgpu::VertexAttribute {
                    format: wgpu::VertexFormat::Float32x4,
                    offset: mem::size_of::<[f32; 12]>() as wgpu::BufferAddress,
                    shader_location: 9,
                },
                wgpu::VertexAttribute {
                    format: wgpu::VertexFormat::Float32x3,
                    offset: mem::size_of::<[f32; 16]>() as wgpu::BufferAddress,
                    shader_location: 10,
                },
                wgpu::VertexAttribute {
                    format: wgpu::VertexFormat::Float32x3,
                    offset: mem::size_of::<[f32; 19]>() as wgpu::BufferAddress,
                    shader_location: 11,
                },
                wgpu::VertexAttribute {
                    format: wgpu::VertexFormat::Float32x3,
                    offset: mem::size_of::<[f32; 22]>() as wgpu::BufferAddress,
                    shader_location: 12,
                },
                wgpu::VertexAttribute {
                    format: wgpu::VertexFormat::Float32,
                    offset: mem::size_of::<[f32; 25]>() as wgpu::BufferAddress,
                    shader_location: 13,
                },
            ],
        }
    }
}

pub struct Instance {
    pub position: cgmath::Vector3<f32>,
    pub rotation: cgmath::Quaternion<f32>,
    pub scale: cgmath::Vector3<f32>,
    pub wind_weight: f32,
}

impl Instance {
    pub fn new(
        position: cgmath::Vector3<f32>,
        rotation: cgmath::Quaternion<f32>,
        scale: cgmath::Vector3<f32>,
    ) -> Self {
        Self {
            position,
            rotation,
            scale,
            wind_weight: 0.0,
        }
    }

    pub fn with_wind(mut self, weight: f32) -> Self {
        self.wind_weight = weight;
        self
    }

    pub fn to_raw(&self) -> InstanceRaw {
        let translation: Matrix4<f32> = cgmath::Matrix4::from_translation(self.position);
        let rotation: Matrix4<f32> = cgmath::Matrix4::from(self.rotation);
        let scale: Matrix4<f32> =
            cgmath::Matrix4::from_nonuniform_scale(self.scale.x, self.scale.y, self.scale.z);

        let normals: Matrix3<f32> = cgmath::Matrix3::from(self.rotation);

        InstanceRaw {
            model: (translation * rotation * scale).into(),
            normals: normals.into(),
            wind_weight: self.wind_weight,
        }
    }
}

impl Default for Instance {
    fn default() -> Self {
        Self {
            position: Vector3::zero(),
            rotation: Quaternion::one(),
            scale: Vector3::new(1.0, 1.0, 1.0),
            wind_weight: 0.0,
        }
    }
}

pub trait DrawLight<'a> {
    fn draw_light_model(
        &mut self,
        model: &'a Model,
        camera_bind_group: &'a wgpu::BindGroup,
        light_bind_group: &'a wgpu::BindGroup,
    );
}

impl<'a, 'b> DrawLight<'b> for wgpu::RenderPass<'a>
where
    'b: 'a,
{
    fn draw_light_model(
        &mut self,
        model: &'a Model,
        camera_bind_group: &'b wgpu::BindGroup,
        light_bind_group: &'b wgpu::BindGroup,
    ) {
        for mesh in &model.meshes {
            let material: &renderer::Material = &model.materials[mesh.material];
            self.set_vertex_buffer(0, mesh.vertex_buffer.slice(..));
            self.set_index_buffer(mesh.index_buffer.slice(..), wgpu::IndexFormat::Uint32);
            self.set_bind_group(0, camera_bind_group, &[]);
            self.set_bind_group(1, light_bind_group, &[]);
            self.set_bind_group(2, &material.bind_group, &[]);
            self.draw_indexed(0..mesh.indices, 0, 0..1);
        }
    }
}

pub trait DrawShadow<'a> {
    fn draw_shadow_model(&mut self, model: &'a Model, light_bind_group: &'a wgpu::BindGroup);
}

impl<'a, 'b> DrawShadow<'b> for wgpu::RenderPass<'a>
where
    'b: 'a,
{
    fn draw_shadow_model(&mut self, model: &'a Model, light_bind_group: &'b wgpu::BindGroup) {
        for mesh in &model.meshes {
            self.set_vertex_buffer(0, mesh.vertex_buffer.slice(..));
            self.set_vertex_buffer(1, model.instance_buffer.slice(..));
            self.set_index_buffer(mesh.index_buffer.slice(..), wgpu::IndexFormat::Uint32);
            self.set_bind_group(0, light_bind_group, &[]);
            self.draw_indexed(0..mesh.indices, 0, 0..model.instances.len() as u32);
        }
    }
}

pub struct Model {
    pub meshes: Vec<renderer::Mesh>,
    pub materials: Vec<renderer::Material>,
    pub instances: Vec<Instance>,
    pub instance_buffer: wgpu::Buffer,
    pub type_model: TypeModel,
}

pub struct ModelDesc<'a> {
    pub path: &'a str,
    pub instances: Vec<Instance>,
    pub kind: TypeModel,
}

impl<'a> ModelDesc<'a> {
    pub fn new(path: &'a str, instances: Vec<Instance>, kind: TypeModel) -> Self {
        Self {
            path,
            instances,
            kind,
        }
    }
}

#[derive(Clone)]
pub enum TypeModel {
    StaticObj,
    PointOfLight,
}