1use std::fs;
4use std::io;
5use std::path::Path;
6
7use winit::event::{Event,WindowEvent};
8use winit::event_loop::ControlFlow;
9
10pub struct Engine {
11 device: wgpu::Device,
12 queue: wgpu::Queue,
13 swap_chain: wgpu::SwapChain,
14 render_pipeline: wgpu::RenderPipeline,
15}
16
17impl Engine {
18 fn draw(&mut self) {
19
20 }
21}
22
23pub struct GameConfig<'a> {
24 pub title: &'a str,
25 pub resolution: (f64, f64),
26 pub vertex_shader_path: &'a Path,
27 pub fragment_shader_path: &'a Path,
28}
29
30pub trait Game: Sized + 'static {
31 fn start(self, config: GameConfig) -> ! {
32 let event_loop = winit::event_loop::EventLoop::new();
37
38 let window = winit::window::WindowBuilder::new()
39 .with_title(config.title)
40 .with_inner_size(winit::dpi::LogicalSize::new(config.resolution.0, config.resolution.1))
41 .with_resizable(false)
42 .with_visible(false)
43 .build(&event_loop)
44 .expect("Failed to create window.");
45
46 let window_dimensions = window.inner_size();
47
48 let surface = wgpu::Surface::create(&window);
49
50 let adapter = pollster::block_on(
55 wgpu::Adapter::request(
56 &wgpu::RequestAdapterOptions {
57 power_preference: wgpu::PowerPreference::Default,
58 compatible_surface: Some(&surface)
59 },
60 wgpu::BackendBit::PRIMARY
61 )
62 ).unwrap();
63
64 let (device, queue) = pollster::block_on(
65 adapter.request_device(
66 &wgpu::DeviceDescriptor {
67 extensions: wgpu::Extensions { anisotropic_filtering: false },
68 limits: wgpu::Limits::default(),
69 }
70 )
71 );
72
73 let swap_chain = device.create_swap_chain(
78 &surface,
79 &wgpu::SwapChainDescriptor {
80 usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
81 format: wgpu::TextureFormat::Bgra8UnormSrgb,
82 width: window_dimensions.width,
83 height: window_dimensions.height,
84 present_mode: wgpu::PresentMode::Mailbox,
85 }
86 );
87
88 let vertex_shader = device.create_shader_module(
93 &wgpu::read_spirv(
94 io::BufReader::new(
95 fs::File::open(config.vertex_shader_path).unwrap()
96 )
97 ).unwrap()
98 );
99
100 let fragment_shader = device.create_shader_module(
101 &wgpu::read_spirv(
102 io::BufReader::new(
103 fs::File::open(config.fragment_shader_path).unwrap()
104 )
105 ).unwrap()
106 );
107
108 let render_pipeline_layout = device.create_pipeline_layout(
113 &wgpu::PipelineLayoutDescriptor {
114 bind_group_layouts: &[]
115 }
116 );
117
118 let render_pipeline = device.create_render_pipeline(
123 &wgpu::RenderPipelineDescriptor {
124 layout: &render_pipeline_layout,
125 vertex_stage: wgpu::ProgrammableStageDescriptor {
126 module: &vertex_shader,
127 entry_point: "main"
128 },
129 fragment_stage: Some(
130 wgpu::ProgrammableStageDescriptor {
131 module: &fragment_shader,
132 entry_point: "main",
133 }
134 ),
135 rasterization_state: Some(
136 wgpu::RasterizationStateDescriptor {
137 front_face: wgpu::FrontFace::Ccw,
138 cull_mode: wgpu::CullMode::None,
139 depth_bias: 0,
140 depth_bias_slope_scale: 0.0,
141 depth_bias_clamp: 0.0,
142 }
143 ),
144 primitive_topology: wgpu::PrimitiveTopology::TriangleList,
145 color_states: &[
146 wgpu::ColorStateDescriptor {
147 format: wgpu::TextureFormat::Bgra8UnormSrgb,
148 color_blend: wgpu::BlendDescriptor::REPLACE,
149 alpha_blend: wgpu::BlendDescriptor::REPLACE,
150 write_mask: wgpu::ColorWrite::ALL,
151 }
152 ],
153 depth_stencil_state: None,
154 vertex_state: wgpu::VertexStateDescriptor {
155 index_format: wgpu::IndexFormat::Uint16,
156 vertex_buffers: &[
157 wgpu::VertexBufferDescriptor {
158 stride: 4 * 4,
159 step_mode: wgpu::InputStepMode::Vertex,
160 attributes: &wgpu::vertex_attr_array![0 => Float4],
161 }
162 ]
163 },
164 sample_count: 1,
165 sample_mask: !0,
166 alpha_to_coverage_enabled: false
167 }
168 );
169
170 let mut engine = Engine {
175 device,
176 queue,
177 swap_chain,
178 render_pipeline,
179 };
180
181 window.set_visible(true);
186
187 event_loop.run(move |event, _, control_flow| {
188 match event {
189 Event::WindowEvent { event, .. } => {
190 match event {
191 WindowEvent::CloseRequested => {
192 *control_flow = ControlFlow::Exit;
193 },
194 _ => {
195 }
197 }
198 },
199 Event::MainEventsCleared => {
200 window.request_redraw()
201 },
202 Event::RedrawRequested(_window_id) => {
203 engine.draw();
204 },
205 _event => {}
206 }
207 })
208 }
209}