diff --git a/simulator/Cargo.toml b/simulator/Cargo.toml index 124fe6b..c7f8121 100644 --- a/simulator/Cargo.toml +++ b/simulator/Cargo.toml @@ -5,7 +5,6 @@ edition = "2021" [dependencies] solar_engine = { path = "../solar_engine" } -winit = "0.30.10" log = "0.4" env_logger = "0.11.8" pollster = "0.4.0" diff --git a/simulator/src/main.rs b/simulator/src/main.rs index 8026e44..007faf0 100644 --- a/simulator/src/main.rs +++ b/simulator/src/main.rs @@ -1,16 +1,9 @@ use cgmath::Rotation3; -use solar_engine::{Application, Body, Simulator}; +use solar_engine::{Application, Body, Key, KeyState, Simulator}; use std::sync::{Arc, RwLock}; use std::thread; -use winit::event::ElementState; -use winit::event::WindowEvent::KeyboardInput; -use winit::event_loop::EventLoop; -use winit::keyboard::Key; -use winit::platform::modifier_supplement::KeyEventExtModifierSupplement; pub async fn run() { - let event_loop = EventLoop::new().unwrap(); - let simulator = Arc::new(RwLock::new(Simulator::new())); { let mut sim = simulator.write().unwrap(); @@ -49,59 +42,58 @@ pub async fn run() { let simulator_clone = simulator.clone(); - let mut window_state = Application::new().on_update(move |state| { - let sim = simulator_clone.read().unwrap(); - let bodies = &sim.bodies; + Application::new() + .on_update(move |state| { + let sim = simulator_clone.read().unwrap(); + let bodies = &sim.bodies; - let instances = bodies - .iter() - .enumerate() - .map(|(i, b)| { - solar_engine::RenderInstance { - position: cgmath::Vector3::new( - (b.position[0] / 1.496e11) as f32, - (b.position[1] / 1.496e11) as f32, - 0.0, - ), - rotation: cgmath::Quaternion::from_angle_z(cgmath::Deg(0.0)), - color: match i { - 0 => [1.0, 1.0, 0.0], // Sun - 1 => [0.0, 0.0, 1.0], // Earth - _ => [0.5, 0.5, 0.5], - }, - scale: 0.05, - shape: solar_engine::Shape::Circle, - } - }) - .collect(); + let instances = bodies + .iter() + .enumerate() + .map(|(i, b)| { + solar_engine::RenderInstance { + position: cgmath::Vector3::new( + (b.position[0] / 1.496e11) as f32, + (b.position[1] / 1.496e11) as f32, + 0.0, + ), + rotation: cgmath::Quaternion::from_angle_z(cgmath::Deg(0.0)), + color: match i { + 0 => [1.0, 1.0, 0.0], // Sun + 1 => [0.0, 0.0, 1.0], // Earth + _ => [0.5, 0.5, 0.5], + }, + scale: 0.05, + shape: solar_engine::Shape::Circle, + } + }) + .collect(); - state.set_instances(instances); - }).on_input(move |_state, event| { - if let KeyboardInput { event, .. } = event { - if event.state == ElementState::Pressed { - return match event.key_without_modifiers().as_ref() { - Key::Character(".") => { + state.set_instances(instances); + }) + .on_input(move |_state, event| { + if event.state == KeyState::Pressed { + return match event.key { + Key::Period => { let mut sim = simulator.write().unwrap(); sim.increase_timewarp(); println!("Timewarp: {}", sim.get_timewarp()); } - Key::Character(",") => { + Key::Comma => { let mut sim = simulator.write().unwrap(); sim.decrease_timewarp(); println!("Timewarp: {}", sim.get_timewarp()); } - Key::Character("-") => { + Key::Minus => { let mut sim = simulator.write().unwrap(); sim.reset_timewarp(); println!("Timewarp: {}", sim.get_timewarp()); } _ => {} - } + }; } - } - }); - - let _ = event_loop.run_app(&mut window_state); + }) + .run(); } fn main() { diff --git a/solar_engine/src/application.rs b/solar_engine/src/application.rs index 4b0e408..5dd7997 100644 --- a/solar_engine/src/application.rs +++ b/solar_engine/src/application.rs @@ -1,17 +1,19 @@ use winit::application::ApplicationHandler; -use winit::event::WindowEvent; +use winit::event::{Modifiers, WindowEvent}; use winit::event_loop::ActiveEventLoop; use winit::window::{Window, WindowId}; +use crate::input::{from_winit_input, InputEvent}; pub struct StateApplication<'a> { state: Option>, + modifiers: Modifiers, update_fn: Option) + 'a>>, - input_fn: Option, &WindowEvent) + 'a>>, + input_fn: Option, &InputEvent) + 'a>>, } impl<'a> StateApplication<'a> { pub fn new() -> Self { - Self { state: None, update_fn: None, input_fn: None } + Self { state: None, update_fn: None, input_fn: None, modifiers: Modifiers::default() } } pub fn on_update) + 'a>(mut self, func: F) -> Self { @@ -19,10 +21,15 @@ impl<'a> StateApplication<'a> { self } - pub fn on_input, &WindowEvent) + 'a>(mut self, func: F) -> Self { + pub fn on_input, &InputEvent) + 'a>(mut self, func: F) -> Self { self.input_fn = Some(Box::new(func)); self } + + pub fn run(mut self) { + let event_loop = winit::event_loop::EventLoop::new().unwrap(); + let _ = event_loop.run_app(&mut self); + } } impl<'a> ApplicationHandler for StateApplication<'a> { @@ -56,13 +63,17 @@ impl<'a> ApplicationHandler for StateApplication<'a> { self.state.as_mut().unwrap().render().unwrap(); } - WindowEvent::KeyboardInput { .. } => { + WindowEvent::KeyboardInput { event, .. } => { if let Some(state) = self.state.as_mut() { if let Some(input_fn) = self.input_fn.as_mut() { - input_fn(state, &event); + let key_event = from_winit_input(&event, self.modifiers); + input_fn(state, &key_event); } } } + WindowEvent::ModifiersChanged(modifiers) => { + self.modifiers = modifiers; + } _ => {} } } diff --git a/solar_engine/src/input.rs b/solar_engine/src/input.rs new file mode 100644 index 0000000..6d95a55 --- /dev/null +++ b/solar_engine/src/input.rs @@ -0,0 +1,191 @@ +use winit::event::{ElementState, KeyEvent, Modifiers}; +use winit::keyboard::{Key as WinitKey, ModifiersKeyState}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Key { + // Symbols + Comma, Period, Minus, Plus, Slash, Backslash, Semicolon, Apostrophe, + LeftBracket, RightBracket, Grave, Equal, + + // Digits + Num0, Num1, Num2, Num3, Num4, Num5, Num6, Num7, Num8, Num9, + + // Letters + A, B, C, D, E, F, G, H, I, J, K, L, M, + N, O, P, Q, R, S, T, U, V, W, X, Y, Z, + + // Arrows + ArrowUp, ArrowDown, ArrowLeft, ArrowRight, + + // Controls + Escape, Enter, Space, Tab, Backspace, + Insert, Delete, Home, End, PageUp, PageDown, + + // Modifier keys + Shift, Control, Alt, Super, + + // Function keys + F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, + + // Numpad + Numpad0, Numpad1, Numpad2, Numpad3, Numpad4, + Numpad5, Numpad6, Numpad7, Numpad8, Numpad9, + NumpadAdd, NumpadSubtract, NumpadMultiply, NumpadDivide, NumpadEnter, + + // Unknown + Unknown, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum KeyState { + Pressed, + Released, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct KeyModifiers { + pub lshift: bool, + pub rshift: bool, + pub lcontrol: bool, + pub rcontrol: bool, + pub lalt: bool, + pub ralt: bool, + pub rsuper_key: bool, + pub lsuper_key: bool, +} + +#[derive(Debug, Clone)] +pub struct InputEvent { + pub key: Key, + pub state: KeyState, + pub text: String, + pub modifiers: KeyModifiers, +} + +pub fn from_winit_input(event: &KeyEvent, modifiers: Modifiers) -> InputEvent { + InputEvent { + key: map_winit_key(&event.logical_key), + state: match event.state { + ElementState::Pressed => KeyState::Pressed, + ElementState::Released => KeyState::Released, + }, + text: event.text.clone().unwrap_or_default().into(), + modifiers: KeyModifiers { + lshift: modifiers.lshift_state() == ModifiersKeyState::Pressed, + rshift: modifiers.rshift_state() == ModifiersKeyState::Pressed, + lcontrol: modifiers.lcontrol_state() == ModifiersKeyState::Pressed, + rcontrol: modifiers.rcontrol_state() == ModifiersKeyState::Pressed, + lalt: modifiers.lalt_state() == ModifiersKeyState::Pressed, + ralt: modifiers.ralt_state() == ModifiersKeyState::Pressed, + rsuper_key: modifiers.rsuper_state() == ModifiersKeyState::Pressed, + lsuper_key: modifiers.lsuper_state() == ModifiersKeyState::Pressed, + }, + } +} + +pub fn map_winit_key(key: &WinitKey) -> Key { + use Key::*; + match key { + WinitKey::Character(s) => match s.as_str() { + "a" | "A" => A, + "b" | "B" => B, + "c" | "C" => C, + "d" | "D" => D, + "e" | "E" => E, + "f" | "F" => F, + "g" | "G" => G, + "h" | "H" => H, + "i" | "I" => I, + "j" | "J" => J, + "k" | "K" => K, + "l" | "L" => L, + "m" | "M" => M, + "n" | "N" => N, + "o" | "O" => O, + "p" | "P" => P, + "q" | "Q" => Q, + "r" | "R" => R, + "s" | "S" => S, + "t" | "T" => T, + "u" | "U" => U, + "v" | "V" => V, + "w" | "W" => W, + "x" | "X" => X, + "y" | "Y" => Y, + "z" | "Z" => Z, + "0" => Num0, + "1" => Num1, + "2" => Num2, + "3" => Num3, + "4" => Num4, + "5" => Num5, + "6" => Num6, + "7" => Num7, + "8" => Num8, + "9" => Num9, + "," => Comma, + "." => Period, + "-" => Minus, + "+" => Plus, + "/" => Slash, + "\\" => Backslash, + ";" => Semicolon, + "'" => Apostrophe, + "[" => LeftBracket, + "]" => RightBracket, + "`" => Grave, + "=" => Equal, + _ => Unknown, + }, + WinitKey::Named(n) => match n.to_text().unwrap_or("") { + "ArrowUp" => ArrowUp, + "ArrowDown" => ArrowDown, + "ArrowLeft" => ArrowLeft, + "ArrowRight" => ArrowRight, + "Escape" => Escape, + "Enter" => Enter, + "Tab" => Tab, + "Space" => Space, + "Backspace" => Backspace, + "Insert" => Insert, + "Delete" => Delete, + "Home" => Home, + "End" => End, + "PageUp" => PageUp, + "PageDown" => PageDown, + "Shift" => Shift, + "Control" => Control, + "Alt" => Alt, + "Super" => Super, + "F1" => F1, + "F2" => F2, + "F3" => F3, + "F4" => F4, + "F5" => F5, + "F6" => F6, + "F7" => F7, + "F8" => F8, + "F9" => F9, + "F10" => F10, + "F11" => F11, + "F12" => F12, + "Numpad0" => Numpad0, + "Numpad1" => Numpad1, + "Numpad2" => Numpad2, + "Numpad3" => Numpad3, + "Numpad4" => Numpad4, + "Numpad5" => Numpad5, + "Numpad6" => Numpad6, + "Numpad7" => Numpad7, + "Numpad8" => Numpad8, + "Numpad9" => Numpad9, + "NumpadAdd" => NumpadAdd, + "NumpadSubtract" => NumpadSubtract, + "NumpadMultiply" => NumpadMultiply, + "NumpadDivide" => NumpadDivide, + "NumpadEnter" => NumpadEnter, + _ => Unknown, + }, + _ => Unknown, + } +} diff --git a/solar_engine/src/lib.rs b/solar_engine/src/lib.rs index d5c35d9..dbc9d36 100644 --- a/solar_engine/src/lib.rs +++ b/solar_engine/src/lib.rs @@ -3,11 +3,21 @@ mod simulator; mod state; mod render; mod application; +mod input; pub use body::Body; + pub use simulator::Simulator; pub use simulator::distance_squared; + pub use application::StateApplication as Application; + pub use render::RenderInstance; pub use render::Shape; -pub use state::State; \ No newline at end of file + +pub use state::State; + +pub use input::Key; +pub use input::map_winit_key; +pub use input::InputEvent; +pub use input::KeyState; \ No newline at end of file