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