reverie-engine 0.6.1

A toy game engine
Documentation
use std::borrow::Cow;

use wgpu as w;

use crate::{model::Vertex, render::vertex::VertexLayout};

use super::{BindingId, texture::WgpuTexture, uniform};

pub static LOC_VERTEX: u32 = 0;
pub static LOC_UV: u32 = 1;
pub static LOC_NORMAL: u32 = 2;
pub static GROUP_TEXTURE: u32 = 0;
pub static BINDING_TEXTURE: BindingId = BindingId::new(GROUP_TEXTURE, 0);
pub static BINDING_SAMPLER: BindingId = BindingId::new(GROUP_TEXTURE, 1);
pub static GROUP_TRANSFORM: u32 = 1;
pub static BINDING_TRANSFORM: BindingId = BindingId::new(GROUP_TRANSFORM, 0);

impl VertexLayout for Vertex {
    const DESC: wgpu::VertexBufferLayout<'static> = w::VertexBufferLayout {
        array_stride: size_of::<Self>() as w::BufferAddress,
        step_mode: w::VertexStepMode::Vertex,
        attributes: &w::vertex_attr_array![
            LOC_VERTEX => Float32x3,
            LOC_UV => Float32x2,
            LOC_NORMAL => Float32x3,
        ],
    };
}

#[derive(Debug)]
pub struct SpriteRenderPipeline {
    pub pipeline: w::RenderPipeline,
    pub texture_bind_group_layout: w::BindGroupLayout,
    pub uniform_bind_group: w::BindGroup,
}

impl SpriteRenderPipeline {
    pub fn new(
        device: &w::Device,
        surface_format: w::TextureFormat,
        transform_uniform_buffer: &w::Buffer,
    ) -> Self {
        let shader = device.create_shader_module(w::ShaderModuleDescriptor {
            label: Some("sprite.wgsl"),
            source: w::ShaderSource::Wgsl(Cow::Borrowed(include_str!("./sprite.wgsl"))),
        });

        let texture_bind_group_layout = create_texture_binding_layout(device);
        let (uniform_bind_group_layout, uniform_bind_group) = uniform::create_mat4_bind_group(
            device,
            transform_uniform_buffer,
            BINDING_TRANSFORM.binding,
        );

        let pipeline_layout = device.create_pipeline_layout(&w::PipelineLayoutDescriptor {
            label: Some("sprite model render pipeline layout"),
            bind_group_layouts: &[
                Some(&texture_bind_group_layout),
                Some(&uniform_bind_group_layout),
            ],
            immediate_size: 0,
        });

        let pipeline = device.create_render_pipeline(&w::RenderPipelineDescriptor {
            label: Some("sprite model render pipeline"),
            layout: Some(&pipeline_layout),
            vertex: w::VertexState {
                module: &shader,
                entry_point: Some("vs_main"),
                compilation_options: Default::default(),
                buffers: &[Vertex::DESC],
            },
            fragment: Some(w::FragmentState {
                module: &shader,
                entry_point: Some("fs_main"),
                compilation_options: Default::default(),
                targets: &[Some(w::ColorTargetState {
                    format: surface_format,
                    blend: Some(w::BlendState {
                        color: w::BlendComponent {
                            src_factor: w::BlendFactor::SrcAlpha,
                            dst_factor: w::BlendFactor::OneMinusSrcAlpha,
                            operation: w::BlendOperation::Add,
                        },
                        alpha: w::BlendComponent::OVER,
                    }),
                    write_mask: w::ColorWrites::ALL,
                })],
            }),
            primitive: w::PrimitiveState {
                topology: w::PrimitiveTopology::TriangleList,
                strip_index_format: None,
                front_face: w::FrontFace::Ccw,
                cull_mode: Some(w::Face::Back),
                unclipped_depth: false,
                polygon_mode: w::PolygonMode::Fill,
                conservative: false,
            },
            depth_stencil: Some(w::DepthStencilState {
                format: w::TextureFormat::Depth32Float,
                depth_write_enabled: Some(true),
                depth_compare: Some(w::CompareFunction::Less),
                stencil: w::StencilState::default(),
                bias: w::DepthBiasState::default(),
            }),
            multisample: w::MultisampleState {
                count: 1,
                mask: !0,
                alpha_to_coverage_enabled: true,
            },
            cache: None,
            multiview_mask: None,
        });

        Self {
            pipeline,
            texture_bind_group_layout,
            uniform_bind_group,
        }
    }
}

fn create_texture_binding_layout(device: &w::Device) -> w::BindGroupLayout {
    WgpuTexture::bind_group_layout(
        device,
        Some("sprite texture bind group layout"),
        BINDING_TEXTURE.binding,
        BINDING_SAMPLER.binding,
    )
}