aleatico 0.1.0

stub package for fennel engine graphics
Documentation
use crate::errors::{AleaticoError, AleaticoResult};
use crate::renderer::pipelines::Pipeline;
use crate::renderer::surface::Surface;
use crate::renderer::vertex::Vertex;
use std::sync::Arc;
use wgpu::{CurrentSurfaceTexture, PresentMode};
use winit::window::Window;

/// GPU rendering context
pub struct GPUContext {
    /// Main surface
    pub surface: Surface,
    /// Subject to change, a random pipeline :3
    pub pipeline: Pipeline,
    /// Window duh
    window: Arc<Window>,
}

const VERTICES: &[Vertex] = &[
    Vertex {
        position: [0.0, 0.5, 0.0],
        color: [1.0, 0.0, 0.0],
    },
    Vertex {
        position: [-0.5, -0.5, 0.0],
        color: [0.0, 1.0, 0.0],
    },
    Vertex {
        position: [0.5, -0.5, 0.0],
        color: [0.0, 0.0, 1.0],
    },
];

impl GPUContext {
    /// Create a new instance of [`GPUContext`]
    pub async fn new(window: Arc<Window>) -> AleaticoResult<GPUContext> {
        let mut surface = Surface::new(window.clone()).await?;
        let pipeline = Pipeline::from_shader_string(
            &mut surface,
            VERTICES,
            include_str!("../../shaders/shader.wgsl"),
        )?;
        Ok(Self {
            surface,
            pipeline,
            window,
        })
    }

    /// Render
    pub fn render(&mut self) -> AleaticoResult<()> {
        self.window.request_redraw();

        if !self.surface.is_configured {
            return Ok(());
        }

        let output = match self.surface.inner.get_current_texture() {
            CurrentSurfaceTexture::Success(surface_texture) => surface_texture,
            CurrentSurfaceTexture::Suboptimal(surface_texture) => {
                drop(surface_texture);

                self.surface
                    .inner
                    .configure(&self.surface.device, &self.surface.config);

                match self.surface.inner.get_current_texture() {
                    CurrentSurfaceTexture::Success(surface_texture) => surface_texture,
                    CurrentSurfaceTexture::Suboptimal(surface_texture) => surface_texture,
                    _ => return Ok(()),
                }
            }
            CurrentSurfaceTexture::Timeout
            | CurrentSurfaceTexture::Occluded
            | CurrentSurfaceTexture::Validation => {
                return Ok(());
            }
            CurrentSurfaceTexture::Outdated => {
                self.surface
                    .inner
                    .configure(&self.surface.device, &self.surface.config);
                return Ok(());
            }
            CurrentSurfaceTexture::Lost => {
                return Err(AleaticoError::LostDevice);
            }
        };

        let view = output
            .texture
            .create_view(&wgpu::TextureViewDescriptor::default());
        let mut encoder =
            self.surface
                .device
                .create_command_encoder(&wgpu::CommandEncoderDescriptor {
                    label: Some("Render Encoder"),
                });

        {
            let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
                label: Some("Render Pass"),
                color_attachments: &[Some(wgpu::RenderPassColorAttachment {
                    view: &view,
                    resolve_target: None,
                    depth_slice: None,
                    ops: wgpu::Operations {
                        load: wgpu::LoadOp::Clear(wgpu::Color {
                            r: 1.0,
                            g: 0.2,
                            b: 0.3,
                            a: 1.0,
                        }),
                        store: wgpu::StoreOp::Store,
                    },
                })],
                depth_stencil_attachment: None,
                occlusion_query_set: None,
                timestamp_writes: None,
                multiview_mask: None,
            });

            render_pass.set_pipeline(&self.pipeline.render_pipeline);
            render_pass.set_vertex_buffer(0, self.pipeline.vertex_buffer.slice(..));
            render_pass.draw(0..3, 0..1);
        }

        self.surface.queue.submit(std::iter::once(encoder.finish()));
        output.present();
        Ok(())
    }

    /// Set VSync status for the renderer
    pub fn vsync(&mut self, enable: bool) {
        self.surface.config.present_mode = if enable {
            PresentMode::AutoVsync
        } else {
            PresentMode::Mailbox
        }
    }
}