From 39b136d7990d5614bc0d197176e77f5b70cb7f1b Mon Sep 17 00:00:00 2001 From: Till Date: Sat, 27 Jul 2019 05:46:42 +0200 Subject: [PATCH] parse input from file --- Cargo.toml | 5 +- config/input.toml | 13 +++++ shaders/line.frag | 2 +- src/input.rs | 135 +++++++++++++++++++++++++++++++++++++++------- src/main.rs | 28 +++++----- 5 files changed, 151 insertions(+), 32 deletions(-) create mode 100644 config/input.toml diff --git a/Cargo.toml b/Cargo.toml index 29f6512..2556222 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,4 +13,7 @@ shaderc = "0.5.0" cgmath = "0.17" winit = "0.19" image = "0.22.0" -tobj = "0.1.8" \ No newline at end of file +tobj = "0.1.8" +serde = "1.0.97" +serde_derive = "1.0.97" +toml = "0.5.1" \ No newline at end of file diff --git a/config/input.toml b/config/input.toml new file mode 100644 index 0000000..78711c1 --- /dev/null +++ b/config/input.toml @@ -0,0 +1,13 @@ +[[button]] +name = "QUIT" +scancode = 1 + +[[button]] +name = "RELOAD_SHADERS" +scancode = 19 +ctrl = true + +[[axis]] +name = "FORWARD" +scancode_positive = 17 +scancode_negative = 31 \ No newline at end of file diff --git a/shaders/line.frag b/shaders/line.frag index f40b64b..31b7126 100644 --- a/shaders/line.frag +++ b/shaders/line.frag @@ -3,5 +3,5 @@ layout(location = 0) out vec4 f_color; void main() { - f_color = vec4(1.0, 0.0, 0.0, 1.0); + f_color = vec4(1.0, 1.0, 0.0, 1.0); } \ No newline at end of file diff --git a/src/input.rs b/src/input.rs index 9598942..4ee17cc 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,5 +1,10 @@ use winit::{ScanCode, ModifiersState, MouseButton, ElementState}; use std::collections::{HashMap}; +use std::fs; + +use toml; + +use serde_derive::{Serialize, Deserialize}; pub struct VirtualButton { pub digital_inputs: Vec @@ -15,9 +20,75 @@ pub struct InputState { pressed_digital: HashMap } +#[derive(Debug, Serialize, Deserialize)] +struct InputConfig { + button: Vec, + axis: Vec, +} + +#[derive(Debug, Serialize, Deserialize)] +struct InputConfigButton { + name: String, + scancode: u32, + ctrl: Option +} + +#[derive(Debug, Serialize, Deserialize)] +struct InputConfigAxis { + name: String, + scancode_positive: u32, + ctrl_positive: Option, + scancode_negative: u32, + ctrl_negative: Option +} + +type InputHashmapEntry<'a> = (&'a DigitalInput, (bool, bool)); impl InputState { - pub fn new() -> InputState { - InputState { virtual_buttons: HashMap::new(), virtual_axes: HashMap::new(), pressed_digital: HashMap::new() } + pub fn new(toml_path: &str) -> InputState { + let mut state = InputState { virtual_buttons: HashMap::new(), virtual_axes: HashMap::new(), pressed_digital: HashMap::new() }; + + let config: InputConfig = toml::from_slice(&fs::read(toml_path).expect("Failed to read input config!")).expect("Failed to parse input config!"); + + let buttons = config.button.iter().for_each(|bn| { + let modifiers = ModifiersState { + shift: false, + ctrl: bn.ctrl.is_some(), + alt: false, + logo: false + }; + let input = DigitalInput::Keyboard(KeyboardInput { scancode: bn.scancode, modifiers }); + if let Some(virtual_button) = state.virtual_buttons.get_mut(&bn.name) { + virtual_button.digital_inputs.push(input); + } else { + state.virtual_buttons.insert(bn.name.clone(), VirtualButton { digital_inputs: vec![input] }); + } + }); + + let axes = config.axis.iter().for_each(|a| { + let modifiers_positive = ModifiersState { + shift: false, + ctrl: a.ctrl_positive.is_some(), + alt: false, + logo: false + }; + let modifiers_negative = ModifiersState { + shift: false, + ctrl: a.ctrl_negative.is_some(), + alt: false, + logo: false + }; + let axis = AxisInput::Digital( + DigitalInput::Keyboard(KeyboardInput { scancode: a.scancode_positive, modifiers: modifiers_positive }), + DigitalInput::Keyboard(KeyboardInput { scancode: a.scancode_negative, modifiers: modifiers_negative }) + ); + if let Some(virtual_axis) = state.virtual_axes.get_mut(&a.name) { + virtual_axis.analog_inputs.push(axis); + } else { + state.virtual_axes.insert(a.name.clone(), VirtualAxis { analog_inputs: vec![axis] }); + } + }); + + return state; } pub fn button_down(self: &Self, button_code: &str) -> bool { @@ -28,12 +99,51 @@ impl InputState { } } - pub fn button_just_pressed(self: &Self, input: VirtualButton) -> bool { - false + pub fn button_just_pressed(self: &Self, button_code: &str) -> bool { + if let Some(input) = self.virtual_buttons.get(button_code) { + self.pressed_digital.iter() + .filter(|(_, (pressed, _))| *pressed) + .any(|(registered_input, _)| input.digital_inputs.iter().any(|digital_input| digital_input == registered_input)) + } else { + false + } } - pub fn button_just_released(self: &Self, input: VirtualButton) -> bool { - false + pub fn button_just_released(self: &Self, button_code: &str) -> bool { + if let Some(input) = self.virtual_buttons.get(button_code) { + self.pressed_digital.iter() + .filter(|(_, (_, released))| *released) + .any(|(registered_input, _)| input.digital_inputs.iter().any(|digital_input| digital_input == registered_input)) + } else { + false + } + } + + pub fn get_axis(self: &Self, axis_code: &str) -> f32 { + if let Some(axis) = self.virtual_axes.get(axis_code) { + axis.analog_inputs.iter().fold(0.0, |fold, item| { + let val = match item { + AxisInput::Analog(_) => 0.0, + AxisInput::Digital(positive_button, negative_button) => self.button_to_float(positive_button) - self.button_to_float(negative_button), + }; + if f32::abs(val) > fold { + val + } else { + fold + } + }) + } else { + assert!(false, format!("Axis {:?} not found!", axis_code)); + 0.0 + } + } + + fn button_to_float(self: &Self, input: &DigitalInput) -> f32 { + if self.pressed_digital.iter().any(|(registered_input, _)| input == registered_input) { + 1.0 + } else { + 0.0 + } } pub fn on_keyboard_event(self: &mut Self, state: ElementState, scancode: ScanCode, modifiers: ModifiersState) { @@ -49,7 +159,7 @@ impl InputState { } } - pub fn finish_update(self: &mut Self) { + pub fn frame_end(self: &mut Self) { self.pressed_digital.iter_mut().for_each(|(_, (recent_press, _))| { if *recent_press { *recent_press = false } }); @@ -68,17 +178,6 @@ pub enum DigitalInput { Mouse(MouseInput) } -impl DigitalInput { - pub fn simple_key(scancode: ScanCode) -> DigitalInput { - DigitalInput::Keyboard(KeyboardInput { scancode, modifiers: ModifiersState { - shift: false, - ctrl: false, - alt: false, - logo: false - } }) - } -} - #[derive(Debug, Eq, PartialEq, Hash)] pub struct KeyboardInput { scancode: ScanCode, diff --git a/src/main.rs b/src/main.rs index f204222..fb34366 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,7 @@ use crate::input::{InputState, VirtualButton, DigitalInput, VirtualAxis, AxisInp mod vulkan; mod input; -const PRINT_KEYBOARD_INPUT: bool = false; +const PRINT_KEYBOARD_INPUT: bool = true; struct TestGame { input: InputState, @@ -16,6 +16,18 @@ struct TestGame { impl Game for TestGame { fn update(self: &mut Self, game_data: &mut GameData) { + // User interaction + if self.input.button_down("QUIT") { + game_data.shutdown = true; + } + + if self.input.button_just_pressed("RELOAD_SHADERS") { + game_data.recreate_pipeline = true; + } + + self.cam_pos.x += self.input.get_axis("FORWARD"); + + // Move game objects game_data.push_constants.time = game_data.start_time.elapsed().unwrap().as_millis() as f32 / 1000.0; let model = Matrix4::from_angle_z(Rad::from(Deg(game_data.push_constants.time * 100.0))); @@ -40,6 +52,8 @@ impl Game for TestGame { game_data.push_constants.projection = proj.into(); game_data.line_push_constants.view = view.into(); game_data.line_push_constants.projection = proj.into(); + + self.input.frame_end(); } fn on_window_event(self: &mut Self, game_data: &mut GameData, event: &Event) { @@ -59,13 +73,6 @@ impl Game for TestGame { } self.input.on_keyboard_event(input.state, input.scancode, input.modifiers); - - if input.state == ElementState::Released && input.modifiers.ctrl && input.scancode == 19 { - game_data.recreate_pipeline = true; - } - if self.input.button_down("QUIT") { - game_data.shutdown = true; - } }, // Event::WindowEvent { event: WindowEvent::MouseInput { device_id, state, button, modifiers }, .. } => { // @@ -77,13 +84,10 @@ impl Game for TestGame { fn main() { let mut game = TestGame { - input: InputState::new(), + input: InputState::new("config/input.toml"), cam_pos: Point3::new(2.0, 2.0, 2.0) }; - game.input.virtual_buttons.insert("QUIT".to_string(), VirtualButton { digital_inputs: vec![DigitalInput::simple_key(1)] }); - game.input.virtual_axes.insert("FORWARD_CAM_AXIS".to_string(), VirtualAxis { analog_inputs: vec![AxisInput::Digital(DigitalInput::simple_key(87), DigitalInput::simple_key(83))] }); - vulkan::init( "models/iski51.obj", (-10..10)