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