pittore 0.2.4

Simple toolkit for 2D visualization based on wgpu.
Documentation
use glam::{Vec2, Vec4};

use crate::{
    backend::RenderState,
    render::{bind_group::AsBindGroup, PipelineSet, PipelineSpec, PIPELINE_FILL},
};

use super::SpriteMaterial;

pub const SHADER_2D_DEFAULT: u32 = 0;

#[repr(C)]
#[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
pub struct Vertex {
    pub position: Vec2,
    pub uv: Vec2,
}

#[repr(C)]
#[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
pub struct Instance {
    pub sprite_rect: Vec4,
    pub matrix2: [f32; 4],
    pub translation: Vec2,
    pub color: [u8; 4],
    pub _padding: [u8; 4],
}

pub struct PipelineBindGroup;

impl AsBindGroup for PipelineBindGroup {
    fn bind_group_layout(device: &wgpu::Device) -> wgpu::BindGroupLayout
    where
        Self: Sized,
    {
        device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
            label: Some("fill_pipeline_bind_group_layout"),
            entries: &[
                wgpu::BindGroupLayoutEntry {
                    binding: 0,
                    visibility: wgpu::ShaderStages::VERTEX,
                    ty: wgpu::BindingType::Buffer {
                        ty: wgpu::BufferBindingType::Storage { read_only: true },
                        has_dynamic_offset: false,
                        min_binding_size: None,
                    },
                    count: None,
                },
                wgpu::BindGroupLayoutEntry {
                    binding: 1,
                    visibility: wgpu::ShaderStages::VERTEX,
                    ty: wgpu::BindingType::Buffer {
                        ty: wgpu::BufferBindingType::Storage { read_only: true },
                        has_dynamic_offset: false,
                        min_binding_size: None,
                    },
                    count: None,
                },
            ],
        })
    }

    fn as_bind_group(&self, render_state: &RenderState) -> wgpu::BindGroup {
        let buffers = &render_state.buffers;

        render_state
            .device
            .create_bind_group(&wgpu::BindGroupDescriptor {
                label: None,
                layout: &Self::bind_group_layout(&render_state.device),
                entries: &[
                    wgpu::BindGroupEntry {
                        binding: 0,
                        resource: buffers.get::<Vertex>().unwrap().as_entire_binding(),
                    },
                    wgpu::BindGroupEntry {
                        binding: 1,
                        resource: buffers.get::<Instance>().unwrap().as_entire_binding(),
                    },
                ],
            })
    }
}

pub fn register_fill_pipeline(render_state: &mut RenderState) {
    render_state.init_buffer::<Vertex>(wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST);
    render_state
        .init_buffer::<Instance>(wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST);

    render_state.register_shader(SHADER_2D_DEFAULT, wgpu::include_wgsl!("shaders/fill.wgsl"));

    let spec: PipelineSpec<PipelineBindGroup, SpriteMaterial> = PipelineSpec {
        shader_id: SHADER_2D_DEFAULT,
        ..Default::default()
    };
    let pipeline = spec.build(render_state);

    let pipeline_set = PipelineSet {
        pipeline,
        pipeline_bind_group: Box::new(PipelineBindGroup),
    };

    render_state.pipelines.insert(PIPELINE_FILL, pipeline_set);
}