1use std::cell::RefCell;
2use std::path::PathBuf;
3use std::rc::Rc;
4use std::sync::Arc;
5use std::time::Instant;
6
7use anyhow::Result;
8use winit::application::ApplicationHandler;
9use winit::event::{ElementState, KeyEvent, WindowEvent};
10use winit::event_loop::{ActiveEventLoop, EventLoop};
11use winit::keyboard::{Key, NamedKey};
12use winit::window::{Window, WindowId};
13
14use crate::renderer::Renderer;
15use crate::renderer::camera::CameraBounds;
16
17use super::input::InputState;
18
19pub struct RenderState {
21 pub renderer: Option<Renderer>,
22 pub input: InputState,
23 pub sprite_commands: Vec<crate::renderer::SpriteCommand>,
24 pub camera_x: f32,
25 pub camera_y: f32,
26 pub camera_zoom: f32,
27 pub camera_bounds: Option<CameraBounds>,
28 pub delta_time: f64,
29}
30
31impl RenderState {
32 pub fn new() -> Self {
33 Self {
34 renderer: None,
35 input: InputState::default(),
36 sprite_commands: Vec::new(),
37 camera_x: 0.0,
38 camera_y: 0.0,
39 camera_zoom: 1.0,
40 camera_bounds: None,
41 delta_time: 0.0,
42 }
43 }
44}
45
46pub struct DevConfig {
48 pub entry_file: PathBuf,
49 pub title: String,
50 pub width: u32,
51 pub height: u32,
52}
53
54pub type FrameCallback = Box<dyn FnMut(&mut RenderState) -> Result<()>>;
57
58struct AppState {
59 window: Option<Arc<Window>>,
60 config: DevConfig,
61 render_state: Rc<RefCell<RenderState>>,
62 frame_callback: FrameCallback,
63 last_frame: Instant,
64 scale_factor: f64,
66}
67
68impl ApplicationHandler for AppState {
69 fn resumed(&mut self, event_loop: &ActiveEventLoop) {
70 if self.window.is_some() {
71 return;
72 }
73
74 let attrs = Window::default_attributes()
75 .with_title(&self.config.title)
76 .with_inner_size(winit::dpi::LogicalSize::new(
77 self.config.width,
78 self.config.height,
79 ));
80
81 let window = Arc::new(
82 event_loop
83 .create_window(attrs)
84 .expect("Failed to create window"),
85 );
86
87 self.scale_factor = window.scale_factor();
88
89 match Renderer::new(window.clone()) {
90 Ok(renderer) => {
91 self.render_state.borrow_mut().renderer = Some(renderer);
92 }
93 Err(e) => {
94 eprintln!("Failed to initialize renderer: {e}");
95 event_loop.exit();
96 return;
97 }
98 }
99
100 self.window = Some(window);
101 self.last_frame = Instant::now();
102 }
103
104 fn window_event(
105 &mut self,
106 event_loop: &ActiveEventLoop,
107 _window_id: WindowId,
108 event: WindowEvent,
109 ) {
110 match event {
111 WindowEvent::CloseRequested => {
112 event_loop.exit();
113 }
114
115 WindowEvent::Resized(new_size) => {
116 let mut state = self.render_state.borrow_mut();
117 if let Some(ref mut renderer) = state.renderer {
118 renderer.resize(new_size.width, new_size.height, self.scale_factor as f32);
119 }
120 }
121
122 WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
123 self.scale_factor = scale_factor;
124 }
125
126 WindowEvent::KeyboardInput {
127 event:
128 KeyEvent {
129 logical_key,
130 state: key_state,
131 ..
132 },
133 ..
134 } => {
135 let key_name = key_to_string(&logical_key);
136 let mut state = self.render_state.borrow_mut();
137 match key_state {
138 ElementState::Pressed => state.input.key_down(&key_name),
139 ElementState::Released => state.input.key_up(&key_name),
140 }
141 }
142
143 WindowEvent::CursorMoved { position, .. } => {
144 let logical_x = position.x as f32 / self.scale_factor as f32;
146 let logical_y = position.y as f32 / self.scale_factor as f32;
147 let mut state = self.render_state.borrow_mut();
148 state.input.mouse_move(logical_x, logical_y);
149 }
150
151 WindowEvent::MouseInput { state: button_state, button, .. } => {
152 let mut state = self.render_state.borrow_mut();
153 let button_id: u8 = match button {
154 winit::event::MouseButton::Left => 0,
155 winit::event::MouseButton::Right => 1,
156 winit::event::MouseButton::Middle => 2,
157 winit::event::MouseButton::Back => 3,
158 winit::event::MouseButton::Forward => 4,
159 winit::event::MouseButton::Other(id) => id.min(255) as u8,
160 };
161 match button_state {
162 ElementState::Pressed => {
163 state.input.mouse_buttons.insert(button_id);
164 let key_name = match button_id {
166 0 => "MouseLeft",
167 1 => "MouseRight",
168 2 => "MouseMiddle",
169 _ => return,
170 };
171 state.input.key_down(key_name);
172 }
173 ElementState::Released => {
174 state.input.mouse_buttons.remove(&button_id);
175 let key_name = match button_id {
176 0 => "MouseLeft",
177 1 => "MouseRight",
178 2 => "MouseMiddle",
179 _ => return,
180 };
181 state.input.key_up(key_name);
182 }
183 }
184 }
185
186 WindowEvent::RedrawRequested => {
187 let now = Instant::now();
188 let dt = now.duration_since(self.last_frame).as_secs_f64();
189 self.last_frame = now;
190
191 {
192 let mut state = self.render_state.borrow_mut();
193 state.delta_time = dt;
194 }
195
196 {
198 let mut state = self.render_state.borrow_mut();
199 if let Err(e) = (self.frame_callback)(&mut state) {
200 eprintln!("Frame callback error: {e}");
201 }
202 }
203
204 {
206 let mut state = self.render_state.borrow_mut();
207 state.input.begin_frame();
208 }
209
210 {
212 let mut state = self.render_state.borrow_mut();
213 let cam_x = state.camera_x;
215 let cam_y = state.camera_y;
216 let cam_zoom = state.camera_zoom;
217 let cam_bounds = state.camera_bounds;
218 let commands = std::mem::take(&mut state.sprite_commands);
219
220 if let Some(ref mut renderer) = state.renderer {
221 renderer.camera.x = cam_x;
222 renderer.camera.y = cam_y;
223 renderer.camera.zoom = cam_zoom;
224 renderer.camera.bounds = cam_bounds;
225 renderer.camera.clamp_to_bounds();
226 renderer.frame_commands = commands;
227
228 if let Err(e) = renderer.render_frame() {
229 eprintln!("Render error: {e}");
230 }
231 }
232 }
233
234 if let Some(ref window) = self.window {
235 window.request_redraw();
236 }
237 }
238
239 _ => {}
240 }
241 }
242
243 fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) {
244 if let Some(ref window) = self.window {
245 window.request_redraw();
246 }
247 }
248}
249
250fn key_to_string(key: &Key) -> String {
252 match key {
253 Key::Named(named) => match named {
254 NamedKey::ArrowUp => "ArrowUp".to_string(),
255 NamedKey::ArrowDown => "ArrowDown".to_string(),
256 NamedKey::ArrowLeft => "ArrowLeft".to_string(),
257 NamedKey::ArrowRight => "ArrowRight".to_string(),
258 NamedKey::Space => "Space".to_string(),
259 NamedKey::Enter => "Enter".to_string(),
260 NamedKey::Escape => "Escape".to_string(),
261 NamedKey::Backspace => "Backspace".to_string(),
262 NamedKey::Tab => "Tab".to_string(),
263 NamedKey::Shift => "Shift".to_string(),
264 NamedKey::Control => "Control".to_string(),
265 NamedKey::Alt => "Alt".to_string(),
266 other => format!("{other:?}"),
267 },
268 Key::Character(c) => c.to_string(),
269 _ => "Unknown".to_string(),
270 }
271}
272
273pub fn run_event_loop(
275 config: DevConfig,
276 render_state: Rc<RefCell<RenderState>>,
277 frame_callback: FrameCallback,
278) -> Result<()> {
279 let event_loop = EventLoop::new()?;
280
281 let mut app = AppState {
282 window: None,
283 config,
284 render_state,
285 frame_callback,
286 last_frame: Instant::now(),
287 scale_factor: 1.0,
288 };
289
290 event_loop.run_app(&mut app)?;
291 Ok(())
292}