1mod gui;
4pub mod resources;
5
6use resources::ResourceManager;
7
8use crate::gui::Framework;
9use log::error;
10use pixels::{Pixels, SurfaceTexture};
11use std::time::{Duration, Instant};
12use winit::dpi::LogicalSize;
13use winit::event::{Event, VirtualKeyCode};
14use winit::event_loop::{ControlFlow, EventLoop};
15use winit::window::{Window, WindowBuilder};
16use winit_input_helper::WinitInputHelper;
17
18pub use egui;
19
20pub struct Engine {
21 window: Window,
22 input: WinitInputHelper,
23 pixels: Pixels,
24 event_loop: EventLoop<()>,
25 framework: Framework,
26
27 resources: ResourceManager
28}
29
30impl Engine {
31 pub fn new(title: &str, w: u32, h: u32, pixel_size: u32) -> Self {
32 env_logger::init();
33 let event_loop = EventLoop::new();
34 let input = WinitInputHelper::new();
35 let window = {
36 let size = LogicalSize::new((w * pixel_size) as f64, (h * pixel_size) as f64);
37 WindowBuilder::new()
38 .with_title(title)
39 .with_inner_size(size)
40 .with_resizable(false)
41 .with_maximized(false)
42 .build(&event_loop)
43 .unwrap()
44 };
45
46 let (pixels, framework) = {
47 let window_size = window.inner_size();
48 let scale_factor = window.scale_factor() as f32;
49 let surface_texture =
50 SurfaceTexture::new(window_size.width, window_size.height, &window);
51 let pixels = Pixels::new(w, h, surface_texture).unwrap();
52 let framework =
53 Framework::new(window_size.width, window_size.height, scale_factor, &pixels);
54
55 (pixels, framework)
56 };
57
58 Self {
59 window,
60 input,
61 pixels,
62 framework,
63 event_loop,
64 resources: ResourceManager::new(),
65 }
66 }
67
68 pub fn run<F: 'static + Fn(FrameContext, &mut ResourceManager)>(mut self, u: F) {
69 let mut frame_count = 0u128;
70 let mut previous_time = Instant::now();
71 const FRAME_TIME: Duration = Duration::from_micros(16666);
72
73 self.event_loop.run(move |event, _, control_flow| {
74 if self.input.update(&event) {
75 if self.input.key_pressed(VirtualKeyCode::Escape) || self.input.quit() {
76 *control_flow = ControlFlow::Exit;
77 return;
78 }
79 self.window.request_redraw();
80 }
81
82 match event {
83 Event::WindowEvent { event, .. } => {
84 self.framework.handle_event(&event);
86 }
87
88 Event::RedrawRequested(_) => {
89 let delta = {
90 let real_delta = previous_time.elapsed();
91 if real_delta < FRAME_TIME {
92 let sleep_time = FRAME_TIME - real_delta;
93 std::thread::sleep(sleep_time);
94
95 FRAME_TIME
96 } else {
97 real_delta
98 }
99 };
100
101 frame_count += 1;
102 previous_time = Instant::now();
103
104 u(FrameContext {
105 frame_count,
106 buffer: self.pixels.get_frame(),
107 delta,
108 }, &mut self.resources);
109 self.framework.prepare(&self.window, &mut self.resources);
110
111 let render_result =
112 self.pixels.render_with(|encoder, render_target, context| {
113 context.scaling_renderer.render(encoder, render_target);
114 self.framework.render(encoder, render_target, context)?;
115
116 Ok(())
117 });
118
119 if render_result
120 .map_err(|e| error!("pixels.render() failed: {}", e))
121 .is_err()
122 {
123 *control_flow = ControlFlow::Exit;
124 }
125 }
126 _ => (),
127 }
128 });
129 }
130
131 pub fn ui<T: 'static + Fn(&egui::Context, &mut ResourceManager)>(mut self, ui: T) -> Self {
132 self.framework.gui = Some(Box::new(ui));
133 self
134 }
135}
136
137pub struct FrameContext<'a> {
138 pub frame_count: u128,
139 pub buffer: &'a mut [u8],
140 pub delta: Duration,
141}