boom 0.1.0

An attempt at a game engine. Not usable atm.
Documentation
//!

use std::fs;
use std::io;
use std::path::Path;

use winit::event::{Event,WindowEvent};
use winit::event_loop::ControlFlow;

pub struct Engine {
    device: wgpu::Device,
    queue: wgpu::Queue,
    swap_chain: wgpu::SwapChain,
    render_pipeline: wgpu::RenderPipeline,
}

impl Engine {
    fn draw(&mut self) {

    }
}

pub struct GameConfig<'a> {
    pub title: &'a str,
    pub resolution: (f64, f64),
    pub vertex_shader_path: &'a Path,
    pub fragment_shader_path: &'a Path,
}

pub trait Game: Sized + 'static {
    fn start(self, config: GameConfig) -> ! {
        //
        // Create window and surface
        //

        let event_loop = winit::event_loop::EventLoop::new();

        let window = winit::window::WindowBuilder::new()
            .with_title(config.title)
            .with_inner_size(winit::dpi::LogicalSize::new(config.resolution.0, config.resolution.1))
            .with_resizable(false)
            .with_visible(false)
            .build(&event_loop)
            .expect("Failed to create window.");

        let window_dimensions = window.inner_size();

        let surface = wgpu::Surface::create(&window);

        //
        // Create adapter, device, and queue
        //

        let adapter = pollster::block_on(
            wgpu::Adapter::request(
                &wgpu::RequestAdapterOptions {
                    power_preference: wgpu::PowerPreference::Default,
                    compatible_surface: Some(&surface)
                },
                wgpu::BackendBit::PRIMARY
            )
        ).unwrap();

        let (device, queue) = pollster::block_on(
            adapter.request_device(
                &wgpu::DeviceDescriptor {
                    extensions: wgpu::Extensions { anisotropic_filtering: false },
                    limits: wgpu::Limits::default(),
                }
            )
        );

        //
        // Create swap chain
        //

        let swap_chain = device.create_swap_chain(
            &surface,
            &wgpu::SwapChainDescriptor {
                usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
                format: wgpu::TextureFormat::Bgra8UnormSrgb,
                width: window_dimensions.width,
                height: window_dimensions.height,
                present_mode: wgpu::PresentMode::Mailbox,
            }
        );

        //
        // Create shader modules
        //

        let vertex_shader = device.create_shader_module(
            &wgpu::read_spirv(
                io::BufReader::new(
                    fs::File::open(config.vertex_shader_path).unwrap()
                )
            ).unwrap()
        );

        let fragment_shader = device.create_shader_module(
            &wgpu::read_spirv(
                io::BufReader::new(
                    fs::File::open(config.fragment_shader_path).unwrap()
                )
            ).unwrap()
        );

        //
        // Create render pipeline layout
        //

        let render_pipeline_layout = device.create_pipeline_layout(
            &wgpu::PipelineLayoutDescriptor {
                bind_group_layouts: &[]
            }
        );

        //
        // Create render pipeline
        //

        let render_pipeline = device.create_render_pipeline(
            &wgpu::RenderPipelineDescriptor {
                layout: &render_pipeline_layout,
                vertex_stage: wgpu::ProgrammableStageDescriptor {
                    module: &vertex_shader,
                    entry_point: "main"
                },
                fragment_stage: Some(
                    wgpu::ProgrammableStageDescriptor {
                        module: &fragment_shader,
                        entry_point: "main",
                    }
                ),
                rasterization_state: Some(
                    wgpu::RasterizationStateDescriptor {
                        front_face: wgpu::FrontFace::Ccw,
                        cull_mode: wgpu::CullMode::None,
                        depth_bias: 0,
                        depth_bias_slope_scale: 0.0,
                        depth_bias_clamp: 0.0,
                    }
                ),
                primitive_topology: wgpu::PrimitiveTopology::TriangleList,
                color_states: &[
                    wgpu::ColorStateDescriptor {
                        format: wgpu::TextureFormat::Bgra8UnormSrgb,
                        color_blend: wgpu::BlendDescriptor::REPLACE,
                        alpha_blend: wgpu::BlendDescriptor::REPLACE,
                        write_mask: wgpu::ColorWrite::ALL,
                    }
                ],
                depth_stencil_state: None,
                vertex_state: wgpu::VertexStateDescriptor {
                    index_format: wgpu::IndexFormat::Uint16,
                    vertex_buffers: &[
                        wgpu::VertexBufferDescriptor {
                            stride: 4 * 4,
                            step_mode: wgpu::InputStepMode::Vertex,
                            attributes: &wgpu::vertex_attr_array![0 => Float4],
                        }
                    ]
                },
                sample_count: 1,
                sample_mask: !0,
                alpha_to_coverage_enabled: false
            }
        );

        //
        // Create engine (container struct)
        //

        let mut engine = Engine {
            device,
            queue,
            swap_chain,
            render_pipeline,
        };

        //
        // Start app
        //

        window.set_visible(true);

        event_loop.run(move |event, _, control_flow| {
            match event {
                Event::WindowEvent { event, .. } => {
                    match event {
                        WindowEvent::CloseRequested => {
                            *control_flow = ControlFlow::Exit;
                        },
                        _ => {
                            // open_albion.update(event);
                        }
                    }
                },
                Event::MainEventsCleared => {
                    window.request_redraw()
                },
                Event::RedrawRequested(_window_id) => {
                    engine.draw();
                },
                _event => {}
            }
        })
    }
}