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) -> ! {
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);
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(),
}
)
);
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,
}
);
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()
);
let render_pipeline_layout = device.create_pipeline_layout(
&wgpu::PipelineLayoutDescriptor {
bind_group_layouts: &[]
}
);
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
}
);
let mut engine = Engine {
device,
queue,
swap_chain,
render_pipeline,
};
window.set_visible(true);
event_loop.run(move |event, _, control_flow| {
match event {
Event::WindowEvent { event, .. } => {
match event {
WindowEvent::CloseRequested => {
*control_flow = ControlFlow::Exit;
},
_ => {
}
}
},
Event::MainEventsCleared => {
window.request_redraw()
},
Event::RedrawRequested(_window_id) => {
engine.draw();
},
_event => {}
}
})
}
}