aleatico 0.1.0

stub package for fennel engine graphics
Documentation
// BEWARE OF THE PIPELINE:
// he/him -> he/they -> she/they -> she/her
use crate::errors::AleaticoResult;
use crate::renderer::surface::Surface;
use crate::renderer::vertex::Vertex;
use std::borrow::Cow;
use std::fs;
use std::path::{Path, PathBuf};
use wgpu::util::DeviceExt;
use wgpu::{ShaderModuleDescriptor, ShaderSource};

/// Struct representing a rendering pipeline
pub struct Pipeline {
    /// Inner `wgpu` render pipeline
    pub render_pipeline: wgpu::RenderPipeline,
    /// Vertex buffer for this pipeline
    pub vertex_buffer: wgpu::Buffer,
}

impl Pipeline {
    /// General helper function to create a shader from a [`ShaderModuleDescriptor`]
    pub fn from_shader_desc(
        surface: &mut Surface,
        vertices: &[Vertex],
        shader: ShaderModuleDescriptor,
    ) -> AleaticoResult<Self> {
        let shader = surface.device.create_shader_module(shader);
        let vertex_buffer = surface
            .device
            .create_buffer_init(&wgpu::util::BufferInitDescriptor {
                label: Some("Vertex Buffer"),
                contents: &*bytemuck::cast_slice(vertices),
                usage: wgpu::BufferUsages::VERTEX,
            });

        let render_pipeline_layout =
            surface
                .device
                .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
                    label: Some("Render Pipeline Layout"),
                    bind_group_layouts: &[],
                    immediate_size: 0,
                });

        let render_pipeline =
            surface
                .device
                .create_render_pipeline(&wgpu::RenderPipelineDescriptor {
                    label: Some("Render Pipeline"),
                    layout: Some(&render_pipeline_layout),
                    vertex: wgpu::VertexState {
                        module: &shader,
                        entry_point: Some("vs_main"),
                        buffers: &[Vertex::desc()],
                        compilation_options: wgpu::PipelineCompilationOptions::default(),
                    },
                    primitive: wgpu::PrimitiveState {
                        topology: wgpu::PrimitiveTopology::TriangleList,
                        strip_index_format: None,
                        front_face: wgpu::FrontFace::Ccw,
                        cull_mode: Some(wgpu::Face::Back),
                        polygon_mode: wgpu::PolygonMode::Fill,
                        unclipped_depth: false,
                        conservative: false,
                    },
                    depth_stencil: None,
                    multisample: wgpu::MultisampleState {
                        count: 1,
                        mask: !0,
                        alpha_to_coverage_enabled: false,
                    },
                    fragment: Some(wgpu::FragmentState {
                        module: &shader,
                        entry_point: Some("fs_main"),
                        targets: &[Some(wgpu::ColorTargetState {
                            format: surface.config.format,
                            blend: Some(wgpu::BlendState::REPLACE),
                            write_mask: wgpu::ColorWrites::ALL,
                        })],
                        compilation_options: wgpu::PipelineCompilationOptions::default(),
                    }),
                    multiview_mask: None,
                    cache: None,
                });

        Ok(Self {
            render_pipeline,
            vertex_buffer,
        })
    }

    /// Create a shader from a file. Recommended to use at runtime for custom shaders
    pub fn from_shader_file(
        surface: &mut Surface,
        vertices: &[Vertex],
        shader: impl Into<PathBuf> + Clone + AsRef<Path>,
    ) -> AleaticoResult<Self> {
        let data = Cow::Owned(fs::read_to_string(shader.clone())?);

        let shader_desc = ShaderModuleDescriptor {
            label: Some("Shader"),
            source: ShaderSource::Wgsl(data),
        };
        let render_pipeline = Pipeline::from_shader_desc(surface, vertices, shader_desc)?;
        Ok(render_pipeline)
    }

    /// Create a shader from a string. Use for built-ins
    pub fn from_shader_string(
        surface: &mut Surface,
        vertices: &[Vertex],
        shader: &str,
    ) -> AleaticoResult<Self> {
        let shader_desc = ShaderModuleDescriptor {
            label: Some("Shader"),
            source: ShaderSource::Wgsl(Cow::Owned(shader.to_string())),
        };
        let render_pipeline = Pipeline::from_shader_desc(surface, vertices, shader_desc)?;
        Ok(render_pipeline)
    }
}