Skip to main content

boom/
lib.rs

1//!
2
3use 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        //
33        // Create window and surface
34        //
35
36        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        //
51        // Create adapter, device, and queue
52        //
53
54        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        //
74        // Create swap chain
75        //
76
77        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        //
89        // Create shader modules
90        //
91
92        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        //
109        // Create render pipeline layout
110        //
111
112        let render_pipeline_layout = device.create_pipeline_layout(
113            &wgpu::PipelineLayoutDescriptor {
114                bind_group_layouts: &[]
115            }
116        );
117
118        //
119        // Create render pipeline
120        //
121
122        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        //
171        // Create engine (container struct)
172        //
173
174        let mut engine = Engine {
175            device,
176            queue,
177            swap_chain,
178            render_pipeline,
179        };
180
181        //
182        // Start app
183        //
184
185        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                            // open_albion.update(event);
196                        }
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}