shadow_engine_2d/
core.rs

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                                // Call user update function
114                                update_fn(&mut self.world, &self.input, &self.time);
115
116                                // Render
117                                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}