1use crate::ecs::World;
2use crate::graphics::Renderer;
3use crate::input::InputState;
4use crate::time::Time;
5use std::sync::Arc;
6use winit::{
7 event::*,
8 event_loop::EventLoop,
9 window::{Window, WindowBuilder},
10};
11
12pub struct Engine {
13 event_loop: Option<EventLoop<()>>,
14 window: Arc<Window>,
15 renderer: Renderer,
16 world: World,
17 input: InputState,
18 time: Time,
19}
20
21pub struct EngineBuilder {
22 title: String,
23 width: u32,
24 height: u32,
25}
26
27impl EngineBuilder {
28 pub fn new() -> Self {
29 Self {
30 title: "Shadow Engine 2D".to_string(),
31 width: 1280,
32 height: 720,
33 }
34 }
35
36 pub fn title(mut self, title: impl Into<String>) -> Self {
37 self.title = title.into();
38 self
39 }
40
41 pub fn size(mut self, width: u32, height: u32) -> Self {
42 self.width = width;
43 self.height = height;
44 self
45 }
46
47 pub fn build(self) -> Engine {
48 let event_loop = EventLoop::new().unwrap();
49 let window = Arc::new(WindowBuilder::new()
50 .with_title(self.title)
51 .with_inner_size(winit::dpi::PhysicalSize::new(self.width, self.height))
52 .build(&event_loop)
53 .unwrap());
54
55 let renderer = pollster::block_on(Renderer::new(window.clone()));
56 let world = World::new();
57 let input = InputState::new();
58 let time = Time::new();
59
60 Engine {
61 event_loop: Some(event_loop),
62 window,
63 renderer,
64 world,
65 input,
66 time,
67 }
68 }
69}
70
71impl Default for EngineBuilder {
72 fn default() -> Self {
73 Self::new()
74 }
75}
76
77impl Engine {
78 pub fn builder() -> EngineBuilder {
79 EngineBuilder::new()
80 }
81
82 pub fn world(&self) -> &World {
83 &self.world
84 }
85
86 pub fn world_mut(&mut self) -> &mut World {
87 &mut self.world
88 }
89
90 pub fn run<F>(mut self, mut update_fn: F)
91 where
92 F: FnMut(&mut World, &InputState, &Time) + 'static,
93 {
94 let event_loop = self.event_loop.take().unwrap();
95
96 event_loop
97 .run(move |event, control_flow| {
98 match event {
99 Event::WindowEvent {
100 ref event,
101 window_id,
102 } if window_id == self.window.id() => {
103 self.input.process_event(event);
104
105 match event {
106 WindowEvent::CloseRequested => control_flow.exit(),
107 WindowEvent::Resized(physical_size) => {
108 self.renderer.resize(*physical_size);
109 }
110 WindowEvent::RedrawRequested => {
111 self.time.update();
112
113 update_fn(&mut self.world, &self.input, &self.time);
115
116 match self.renderer.render(&self.world) {
118 Ok(_) => {}
119 Err(wgpu::SurfaceError::Lost) => {
120 self.renderer.resize(self.renderer.size())
121 }
122 Err(wgpu::SurfaceError::OutOfMemory) => control_flow.exit(),
123 Err(e) => eprintln!("Render error: {:?}", e),
124 }
125
126 self.input.end_frame();
127 }
128 _ => {}
129 }
130 }
131 Event::AboutToWait => {
132 self.window.request_redraw();
133 }
134 _ => {}
135 }
136 })
137 .unwrap();
138 }
139}